Loaded required libraries
libraries
knitr
FactoMineR
factoextra
gprofiler2
pheatmap
biomaRt

Synopsis du projet

Travail demandé

Le but de ce travail est de mettre en oeuvre les méthodes vues dans le module 3 “R et statistiques” pour explorer le jeu de données de Pavkovic, et de rendre un rapport d’analyse au format .Rmd.

Nous fournissons ci-dessous une trame avec les principales sections attendues. Certaines contiennent déjà du code. Vous devrez en compléter d’autres. Sentez-vous libres d’adapter cette trame ou d’y ajouter des analyses complémentaires si elles vous aident à interpréter vos résultats.

Remise du rapport

Date: le 17 mai 2021 minuit. Si vous anticipez un problème pour remettre le rapport à cette date contactez-nous aussi rapidement que possible pour que nous puissions prévoir une remise plus tardive.

  • Commencez par renommer le fichier .Rmd en remplaçant Prenom-NOM par vos nom et prénom.
  • Le rapport est attendu en formats .Rmd + .HTML (en gardant l’option self_contained de l’en-tête activée).
  • Déposez les fichiers dans un sous-dossier de vote compte du cluster. Attention, veillez à respecter précisément cette structure de chemin car nous nous baserons dessus pour récupérer vos résultats.

    /shared/projects/dubii2021/[login]/m3-stat-R/mini-projet

Critères d’évaluation

  • Reproductibilité des analyses: nous tenterons de regénérer le rapport HTML à partir de votre Rmd, en partant de notre compte sur le serveur IFB.
  • Manipulation des objets R
  • Mobilisation des méthodes statistiques vues au cours
  • Pertinence des interprétations statistiques
  • Pertinence des interprétations biologiques
  • Clarté de la rédaction
  • Clarté des illustrations (figures et tableaux): graphismes, légendes …

Nous vous encourageons à assurer la lisibilité de votre code (syntaxe, nommage des variables, commentaires de code)

Objectifs scientifiques

Nous partons du même jeu de données Fil Rouge de ce module issues de la publication Pavkovic, M., Pantano, L., Gerlach, C.V. et al. Multi omics analysis of fibrotic kidneys in two mouse models. Sci Data 6, 92 (2019). https://doi.org/10.1038/s41597-019-0095-5

Rappel sur les échantillons:

Deux modèles de fibrose rénale chez la souris sont étudiés:

  1. Le premier est un modèle de néphropathie réversible induite par l’acide folique (folic acid (FA)). Les souris ont été sacrifiées avant le traitement (normal), puis à jour 1, 2, 7 et 14 (day1,…) après une seule injection d’acide folique.

  2. Le second est un modèle irréversible induit chrirurgicalement (unilateral ureteral obstruction (UUO)). les souris ont été sacrifiées avant obstruction (day 0) et à 3, 7 et 14 jours après obstruction par ligation de l’uretère du rein gauche.

A partir de ces extraits de rein, l’ARN messager total et les petits ARNs ont été séquencés et les protéines caratérisées par spectrométrie de masse en tandem (TMT).

But scientifique: Dans le tutoriel sur les dataframes, vous avez travaillé sur les données de transcriptome du modèle UUO. Dans ce mini-projet, vous allez travailler sur les données du transcriptome du modèle FA afin de regrouper les observations (échantillon) et les gènes selon des profils d’expression similaires.

Votre projet se décompose en 5 parties dont 3 seront à réaliser par:

  1. Statitiques descriptives des données brutes: commandes fournies
  2. Normalisation des données : commandes fournies
  3. Statistiques descriptives des données normalisées: à vous de jouer
  4. Analyse de regroupement des données: à vous de jouer
  5. Analyse d’enrichissement fonctionnel: à vous de jouer

1. Les données brutes

Vous n’avez rien à coder ici. Le code est fourni.

Chargement des données brutes

Le bloc suivant contient une fonction qui permet de télécharger un fichier dans l’espace de travail, sauf s’il est déjà présent. Nous l’utiliserons ensuite pour télécharger les données à analyser en évitant de refaire le transfert à chaque exécution de l’analyse.

Nous téléchargeons deux fichiers dans un dossier local ~/m3-stat-R/pavkovic_analysis (vous pouvez changer le nom ou chemin dans le chunk ci-dessous), et les chargeons dans les data.frames suivants:

  • Données brutes de transcriptome: fa_expr_raw
  • Métadonnées: fa_meta

Nous regardons la structure de chaque dataframe.

'data.frame':   46679 obs. of  18 variables:
 $ day1_1  : num  2278.8 0 36.3 13.2 0 ...
 $ day1_2  : num  1786.5 0 22.15 7.15 27.9 ...
 $ day1_3  : num  2368.62 0 39.48 1.12 6.9 ...
 $ day14_1 : num  627.758 0 14.471 0.867 5.692 ...
 $ day14_2 : num  559.2 0 10.2 0 1.9 ...
 $ day14_3 : num  611.434 0 31.691 0 0.655 ...
 $ day2_1  : num  2145.22 0 300.56 1.71 57.38 ...
 $ day2_2  : num  262.45 0 4.77 0 0 ...
 $ day2_3  : num  745.84 0 123.9 5.26 38.9 ...
 $ day3_1  : num  987.185 0 51.856 0.802 8.931 ...
 $ day3_2  : num  1077.65 0 8.43 0 6.97 ...
 $ day3_3  : num  1335.1 0 69.9 0 0 ...
 $ day7_1  : num  1096.08 0 6.67 0 7.94 ...
 $ day7_2  : num  1035.846 0 6.955 0.849 101.648 ...
 $ day7_3  : num  1090.04 0 42.58 1.71 0.65 ...
 $ normal_1: num  483.23 0 7.35 0.86 32.06 ...
 $ normal_2: num  1842.1 0 11.2 0 10.4 ...
 $ normal_3: num  475.7 0 1.03 0 0 ...
'data.frame':   18 obs. of  5 variables:
 $ dataType    : chr  "transcriptome" "transcriptome" "transcriptome" "transcriptome" ...
 $ sampleName  : chr  "day14_1" "day14_2" "day14_3" "day1_1" ...
 $ condition   : chr  "day14" "day14" "day14" "day1" ...
 $ sampleNumber: int  1 2 3 1 2 3 1 2 3 1 ...
 $ color       : chr  "#FF4400" "#FF4400" "#FF4400" "#BBD7FF" ...

Les deux fichiers ne donnent pas les observations de l’échantillon dans le même ordre:

 [1] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE

Nous les réorganisons les échantillons dans l’ordre de l’expérience: condition normale, puis day 1 à 14 avec les 3 réplicats.

Metdata for Pavkovoc FA transcriptome
dataType sampleName condition sampleNumber color
16 transcriptome normal_1 normal 1 #BBFFBB
17 transcriptome normal_2 normal 2 #BBFFBB
18 transcriptome normal_3 normal 3 #BBFFBB
4 transcriptome day1_1 day1 1 #BBD7FF
5 transcriptome day1_2 day1 2 #BBD7FF
6 transcriptome day1_3 day1 3 #BBD7FF
7 transcriptome day2_1 day2 1 #F0BBFF
8 transcriptome day2_2 day2 2 #F0BBFF
9 transcriptome day2_3 day2 3 #F0BBFF
10 transcriptome day3_1 day3 1 #FFFFDD
11 transcriptome day3_2 day3 2 #FFFFDD
12 transcriptome day3_3 day3 3 #FFFFDD
13 transcriptome day7_1 day7 1 #FFDD88
14 transcriptome day7_2 day7 2 #FFDD88
15 transcriptome day7_3 day7 3 #FFDD88
1 transcriptome day14_1 day14 1 #FF4400
2 transcriptome day14_2 day14 2 #FF4400
3 transcriptome day14_3 day14 3 #FF4400

=> Ainsi, nous avons un jeu de données avec un échantillon de 18 observations et des données d’expression de 46679 gènes.

Statistiques descriptives

Dans le tutorial sur les dataframes sur le jeu de données “uuo” (relisez le corrigé), nous vous avons demandé de créer un data.frame qui collecte les statistiques par gène et par échantillon. Nous vous demandons de réaliser une étude similaire sur les données “FA” avant et après normalisation inter-échantillons des données. Le code de la partie avant normalisation est donné.

Par échantillon avant normalisation

Nous créons un data.frame nommé sample_stat_prenorm qui comporte une ligne par échantillon et une colonne par statistique. Nous calculons les statistiques suivantes sur les valeurs log2 d’expression de chaque échantillon:

  • moyenne
  • écart-type
  • intervalle inter-quartiles
  • premier quartile
  • médiane
  • troisième quartile
  • maximum
  • nombre de valeurs nulles

Il est affiché avec la fonction kable().

Sample-wise statistics before normalisation.
mean sd iqr Q1 median Q3 max null
normal_1 576.2992 57643.81 46.38417 0 1.166694 46.38417 11777395 21415
normal_2 1172.5615 111509.82 103.13749 0 2.975840 103.13749 22658521 20203
normal_3 531.8620 57203.96 41.80724 0 1.081680 41.80724 11636735 21660
day1_1 663.0580 65219.36 58.76393 0 1.105540 58.76393 13174979 21700
day1_2 1224.5149 123140.72 111.71166 0 3.053561 111.71166 25118595 20152
day1_3 1368.6144 133450.04 122.38187 0 3.766666 122.38187 27255572 19621
day2_1 1161.7628 103598.87 127.04744 0 3.501480 127.04744 21036079 19978
day2_2 223.8844 20431.97 14.54242 0 0.000000 14.54242 4037963 24446
day2_3 628.4406 57480.66 63.36112 0 1.478198 63.36112 11662570 21455
day3_1 649.8389 55210.88 77.84371 0 2.076066 77.84371 11170233 20772
day3_2 514.8649 42768.34 74.16479 0 1.941705 74.16479 8612320 21142
day3_3 854.0997 80565.29 104.95124 0 2.975772 104.95124 16484449 20287
day7_1 576.2437 53112.82 90.51017 0 2.256164 90.51017 10690493 20865
day7_2 510.2741 47373.18 80.57478 0 2.537673 80.57478 9682527 20467
day7_3 604.9701 59072.56 83.50019 0 2.874706 83.50019 12164986 20045
day14_1 540.2640 54481.09 65.01270 0 2.025707 65.01270 11178198 20496
day14_2 681.9987 74825.35 69.05744 0 2.032894 69.05744 15430799 20870
day14_3 562.5697 56026.62 75.11681 0 2.247271 75.11681 11575718 20396

Par gène avant normalisation

Nous créons ci-dessous un data.frame nommé gene_stat_prenorm qui comporte une ligne par gène et une colonne par statistique. Nous calculons les statistiques suivantes sur les valeurs log2 de chaque gène.

  • moyenne
  • médiane
  • écart-type
  • premier quartile
  • troisième quartile
  • maximum
  • nombre de valeurs nulles
  • intervalle inter-quartiles

Ces résultats sont stockés dans un data.frame avec 1 ligne par échantillon et 1 colonne par statistique. Nous affichons les lignes 100 à 109 de ce tableau de statistiques avec la fonction kable().

Gene-wise statistics before normalisation
mean sd iqr Q1 median Q3 max null
ENSMUSG00000000567 320.336744 286.399084 364.362298 91.046357 261.659973 455.40866 1052.68945 0
ENSMUSG00000000568 857.348825 694.432189 282.978949 575.571199 711.096105 858.55015 3406.45030 0
ENSMUSG00000000579 422.075702 162.290415 157.732606 340.417017 447.572742 498.14962 728.51737 0
ENSMUSG00000000581 498.978227 248.612029 259.324338 320.599085 471.269224 579.92342 942.51104 0
ENSMUSG00000000594 2113.558334 1237.521694 937.571105 1400.226182 1868.718762 2337.79729 6408.96044 0
ENSMUSG00000000600 2299.978163 911.222891 1480.192582 1719.874980 2093.572929 3200.06756 3674.18811 0
ENSMUSG00000000605 325.552118 169.456624 195.879561 221.735904 282.608205 417.61546 791.31256 0
ENSMUSG00000000606 9.929258 32.151350 2.736779 1.178311 1.934744 3.91509 138.48677 4
ENSMUSG00000000617 18.804116 9.470819 13.654701 12.188276 18.150391 25.84298 36.00235 0
ENSMUSG00000000627 15.623306 14.341852 12.308127 4.780913 10.064895 17.08904 46.29752 0

2. Filtrage et normalisation des données

Vous n’avez rien à coder ici. Le code est fourni.

Il existe plusieurs façons de normaliser les données de transcriptome vues dans les modules 4 et 5 (cf. total counts, quantiles, TMM, RLE, limma voom,…), mais nous avons choisi ici une solution simple tout en étant robuste pour normaliser les données en standardisant le 3ème quantile.

La méthode choisie ici consiste à :

  1. Ecarter les gènes “non-détectés”, c’est-à-dire ceux ayant des valeurs nulles dans au moins 90% des échantillons.

  2. Ecarter les gènes à peine exprimés, c’est-à-dire ceux ayant une valeur moyenne < 10 (arbitrairement).

  3. Standardiser les échantillons sur le 3ème quartile des gènes restants: on divise les comptages bruts par le 3ème quartile de l’échantillon et on multiplie par le 3ème quartile de l’ensemble des échantillons.

  4. Normaliser les comptages (au sens propre, c’est-à-dire rapprocher leur distribution de la distribution gaussienne) par une transformation logarithmique (log2).

Nous fournissons ci-dessous le code.

Standardisation entre échantillons

Nous appliquons ici une méthode simple mais efficace de standardisation

Third quartile of the filtered counts after inter-sample standardisation of the third quartiles.
Q3_standardised
normal_1 364.9332
normal_2 364.9332
normal_3 364.9332
day1_1 364.9332
day1_2 364.9332
day1_3 364.9332
day2_1 364.9332
day2_2 364.9332
day2_3 364.9332
day3_1 364.9332
day3_2 364.9332
day3_3 364.9332
day7_1 364.9332
day7_2 364.9332
day7_3 364.9332
day14_1 364.9332
day14_2 364.9332
day14_3 364.9332

Transformation log2

Nous appliquons une transformation en log2 des données brutes, après avoir ajouté un epsilon \(\epsilon = 1\) (les valeurs nulles seront donc représentées par un log2(counts) valant \(0\). Nous stockons le résultat dans un data.frame nommé fa_expr_log2.

Nous affichons un fragment des tableaux fa_expr_raw et fa_expr_log2 en sélectionnant les lignes 100 à 109 et les colonnes 5 à 10, afin de nous assurer que la transformation en log2 a bien fonctionné.

Fragment des données transcriptomiques brutes
day1_2 day1_3 day2_1 day2_2 day2_3 day3_1
ENSMUSG00000000567 599.648075 304.093177 1052.689447 106.995584 347.13842 479.59911
ENSMUSG00000000568 1008.026306 1349.126716 818.257157 116.136417 3406.45030 766.09722
ENSMUSG00000000579 599.832586 500.735597 473.399472 36.258005 410.57787 347.05054
ENSMUSG00000000581 942.511039 744.646735 546.260344 87.788535 319.12679 461.45732
ENSMUSG00000000594 3063.845705 2743.404374 2283.051270 1115.588250 1491.61384 1576.68451
ENSMUSG00000000600 3341.854530 3561.805180 3674.188108 589.840068 1399.10751 3446.01856
ENSMUSG00000000605 791.312561 558.710943 489.579657 77.008213 256.00200 282.80077
ENSMUSG00000000606 4.785252 6.566374 3.970399 0.000000 138.48677 0.00000
ENSMUSG00000000617 15.839486 29.138902 30.228506 6.670500 18.27493 13.41152
ENSMUSG00000000627 36.673777 35.967747 46.297517 2.878275 17.03638 15.45854
Fragment des données transcriptomiques après transformation log2
day1_2 day1_3 day2_1 day2_2 day2_3 day3_1
ENSMUSG00000000711 9.709367 9.861557 9.287726 12.335149 9.755002 10.013232
ENSMUSG00000000724 5.904466 6.218882 4.464461 5.782181 5.701477 5.803482
ENSMUSG00000000731 5.203571 5.404039 4.963615 5.970908 4.299021 4.505637
ENSMUSG00000000732 5.398925 8.209062 2.126857 3.751910 6.948597 4.970987
ENSMUSG00000000738 8.520431 8.430289 8.263532 7.909466 8.250468 7.455809
ENSMUSG00000000740 11.228789 11.320488 11.117466 10.630164 11.595716 10.156658
ENSMUSG00000000743 7.882486 7.268069 8.646853 10.469226 6.135917 7.385994
ENSMUSG00000000751 7.302103 8.404643 7.851161 6.677037 8.189071 7.123055
ENSMUSG00000000753 0.000000 2.885227 2.310527 0.000000 0.000000 4.605696
ENSMUSG00000000759 8.296064 8.620921 7.830522 9.377892 9.333861 10.038888

3. Statistiques descriptives sur les données normalisées

A vous de jouer!

Annotation des gènes

Chaque gène étant donné par son identifiant dans la base de données ENSEMBL vous utiliserez le paquet biomaRt de bioconductor pour ajouter des annotations : symbole, chromosome, coordonnées génomiques, brin. Suivez pas à pas la méthode proposée (certaines étapes peuvent prendre quelques minutes):

  • chargez le paquet biomaRt, voire installer-le uniquement si nécessaire. Indiquez le code à l’emplacement adéquat dans de .Rmd.

  • sélectionnez la base de données ENSEMBL avec la fonction useMart(). Attention à choisir le bon génome avec l’agument dataset: mmusculus_gene_ensembl

  • avec la fonction getBM() récupérez de la base de données ENSEMBL les champs demandés (pour symbole utilisez external_gene_name) en appliquant “ensembl_geneid” pour l’agument filter et en indiquant pour l’argument values le vecteur des identifiants des gènes présents dans le dataframe gene_stat_norm. Vous obtenez un dataframe.

A présent, ajoutez au dataframe gene_stat_norm en 1ères colonnes les annotations retrouvées grâce à biomaRt. Attention, certains gènes ne sont pas retrouvés dans la version d’ENSEMBL sur biomaRt donc laissez des NA comme données manquantes dans ce cas. Nous vous recommandons d’utiliser la function merge() de R base ou bien left_join() de dplyr pour fusionner les deux dataframes en un seul.

Challenge falcultatif:

Réordonnez les gènes par position génomique et affichez les lignes 5 premières et 5 dernières lignes de ce tableau de statistiques.

Distribution des données

  • Dessinez sous forme d’un histogramme la distribution des valeurs après normalisation (tous échantillons confondus)
Distribution of expression values (log2 counts) after gene filtering and standardisation on the sample-wise third-quartile of non-null values. The vertical line highlights the mean value.

Distribution of expression values (log2 counts) after gene filtering and standardisation on the sample-wise third-quartile of non-null values. The vertical line highlights the mean value.

  • Dessinez un box plot par échantillon avant et après normalisation, et commentez la façon dont l’effet de la normalisation apparaît sur ces graphiques.
Box plots showing the impact of normalisation

Box plots showing the impact of normalisation

4. Analyse de regroupement des données

A vous de jouer!

Sélection de gènes d’expression élevée et variable

Pour réduire le nombre de gènes, nous allons écarter les gènes faiblement exprimés (log2 moyen inférieur à 4), et ne retenir que ceux qui montrent des variations importantes entre échantillons. Pour ce dernier critère, nous nous basons sur la variance.

Sélectionnez les gènes ayant un niveau log2 moyen minimal supérieur à 5 (\(m > 5\)) et une variance supérieure à 2 (\(s^2 > 2\)). Note: ces valeurs sont parfaitement arbitraires, elles ont été choisies pour obtenir un nombre raisonnable de gènes.

[1] "Selected genes: 690"

Dessinez des histogrammes des valeurs d’expression avant et après cette sélection de gènes, et commentez les différences.

Distribution of expression values before and after gene selection

Distribution of expression values before and after gene selection

Dessinez un box plot par échantillon des valeurs d’expression avant et après sélection des gènes, et commentez le résultat.

Box plots of standardised expression values before and after gene selection.

Box plots of standardised expression values before and after gene selection.

ACP

Dessinez un plot ACP des échantillons en les colorant par condition avant et après normalisation.

  • avec les comptages bruts de la matrice d’expression initiale (\(fa_expr\))
PC plot of the samples from the raw expression values of all genes.

PC plot of the samples from the raw expression values of all genes.

  • avec la matrice de valeurs normalisées des gènes filtrés
PC plot of the samples from normalised counts, before gene selection.

PC plot of the samples from normalised counts, before gene selection.

  • avec la matrice finale (transformation log2, filtre des gènes non-détectés, standardisation et sélection des gènes fortement exprimés et à haut coefficient de variation)
PC plot of the samples from normalised values, after gene selection.

PC plot of the samples from normalised values, after gene selection.

Clustering

  • Calculez les matrices de distance entre échantillons, en utilisant respectivement les distances euclidienne (dist()), coefficient de Pearson (cor(, method = "pearson")) et de Spearman (cor(, method = "spearman")).
  • Effectuez un clustering hiérarchique des échantillons, en utilisant le critère “complete” pour l’agglomération. Comparez les arbres d’échantillons obtenus avec ces trois métriques et choisissez celle qui vous paraît la plus pertinente.
Sample tree with three alternative distance metrics: Euclidiant distance (left), Pearson correlation (center), Spearman correlation (right).?

Sample tree with three alternative distance metrics: Euclidiant distance (left), Pearson correlation (center), Spearman correlation (right).?

  • Effectuez un clustering hiérarchique des gènes en utilisant la distance basée sur le coefficient de Pearson et le critère de Ward

  • Dessinez un arbre avec le résultat du clustering des gènes et commentez sa structure. Si vous deviez choisir de façon arbitraire un nombre de clusters, que choisiriez-vous ? Pourquoi ? Pas de panique, nous pouvons assumer ici que la réponse comporte une part de subjectivité.

  • Dessinez une heatmap du résultat, en sélectionnant les deux résultats de clustering ci-dessus pour les gènes et les échantillons.
Heatmap showing the biclustering of genes and samples.

Heatmap showing the biclustering of genes and samples.

  • Dessinez une heatmap du résultat, en affichant un arbre sur les gènes mais pas sur les échantillons

Interprétez les résultats en quelques phrases.

5. Enrichissement fonctionnel

A vous de jouer!

Effectuez une analyse d’enrichissement fonctionnel avec les principaux clusters obtenus dans la section précédente.

[1] "result" "meta"  
 [1] "query"                 "significant"           "p_value"               "term_size"             "query_size"            "intersection_size"     "precision"             "recall"                "term_id"               "source"                "term_name"             "effective_domain_size"
[13] "source_order"          "parents"              
Length Class Mode
result 14 data.frame list
meta 5 -none- list
Top 10 most significant enriched functional classes
query significant p_value term_size query_size intersection_size precision recall term_id source term_name effective_domain_size source_order parents
60 query_1 TRUE 0.000000000682655 92 266 20 0.075 0.217 KEGG:04610 KEGG Complement and coagulation cascades 8787 299 KEGG:00000
1 query_1 TRUE 0.000000039452735 272 320 31 0.097 0.114 GO:0006955 GO:BP immune response 11240 2901 GO:0002376, GO:0050896
2 query_1 TRUE 0.000000161876615 331 320 33 0.103 0.100 GO:0002376 GO:BP immune system process 11240 1038 GO:0008150
61 query_1 TRUE 0.000000212705027 116 266 19 0.071 0.164 KEGG:05150 KEGG Staphylococcus aureus infection 8787 416 KEGG:00000
26 query_1 TRUE 0.000006518770910 627 204 42 0.206 0.067 GO:0071944 GO:CC cell periphery 7218 3147 GO:0110165
27 query_1 TRUE 0.000006518770910 10 204 6 0.029 0.600 GO:0042613 GO:CC MHC class II protein complex 7218 2067 GO:0042611
28 query_1 TRUE 0.000009336222258 11 204 6 0.029 0.545 GO:0042611 GO:CC MHC protein complex 7218 2065 GO:0098797
62 query_1 TRUE 0.000017723712072 113 266 16 0.060 0.142 KEGG:04668 KEGG TNF signaling pathway 8787 321 KEGG:00000
63 query_1 TRUE 0.000017723712072 86 266 14 0.053 0.163 KEGG:05323 KEGG Rheumatoid arthritis 8787 460 KEGG:00000
125 query_1 TRUE 0.000029996303079 41 174 11 0.063 0.268 WP:WP3626 WP Microglia Pathogen Phagocytosis Pathway 4526 46 WP:000000
[1] "query_metadata"  "result_metadata" "genes_metadata"  "timestamp"       "version"        

Conclusions générales

Résumez en quelques phrases vos conclusions à partir des résultats obtenus.

Session info

R version 4.0.2 (2020-06-22)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Mojave 10.14.6

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] biomaRt_2.44.4   pheatmap_1.0.12  gprofiler2_0.2.0 factoextra_1.0.7 ggplot2_3.3.3    FactoMineR_2.4   knitr_1.32      

loaded via a namespace (and not attached):
  [1] bitops_1.0-6         bit64_4.0.5          RColorBrewer_1.1-2   progress_1.2.2       httr_1.4.2           tools_4.0.2          backports_1.2.1      bslib_0.2.4          utf8_1.2.1           R6_2.5.0             DT_0.18              DBI_1.1.1            lazyeval_0.2.2       BiocGenerics_0.34.0 
 [15] colorspace_2.0-0     withr_2.4.2          tidyselect_1.1.0     prettyunits_1.1.1    bit_4.0.4            curl_4.3             compiler_4.0.2       Biobase_2.48.0       flashClust_1.01-2    xml2_1.3.2           plotly_4.9.3         labeling_0.4.2       sass_0.3.1           scales_1.1.1        
 [29] askpass_1.1          rappdirs_0.3.3       stringr_1.4.0        digest_0.6.27        foreign_0.8-81       rmarkdown_2.7        rio_0.5.26           pkgconfig_2.0.3      htmltools_0.5.1.1    dbplyr_2.1.1         fastmap_1.1.0        highr_0.9            readxl_1.3.1         htmlwidgets_1.5.3   
 [43] rlang_0.4.10         RSQLite_2.2.6        shiny_1.6.0          farver_2.1.0         jquerylib_0.1.3      generics_0.1.0       jsonlite_1.7.2       crosstalk_1.1.1      zip_2.1.1            dplyr_1.0.5          car_3.0-10           RCurl_1.98-1.3       magrittr_2.0.1       leaps_3.1           
 [57] Rcpp_1.0.6           munsell_0.5.0        S4Vectors_0.26.1     fansi_0.4.2          abind_1.4-5          lifecycle_1.0.0      scatterplot3d_0.3-41 stringi_1.5.3        yaml_2.2.1           carData_3.0-4        MASS_7.3-53.1        BiocFileCache_1.12.1 grid_4.0.2           blob_1.2.1          
 [71] promises_1.2.0.1     parallel_4.0.2       ggrepel_0.9.1        forcats_0.5.1        crayon_1.4.1         lattice_0.20-41      haven_2.4.0          hms_1.0.0            pillar_1.6.0         ggpubr_0.4.0         ggsignif_0.6.1       stats4_4.0.2         XML_3.99-0.6         glue_1.4.2          
 [85] evaluate_0.14        data.table_1.14.0    httpuv_1.5.5         vctrs_0.3.7          cellranger_1.1.0     gtable_0.3.0         openssl_1.4.3        purrr_0.3.4          tidyr_1.1.3          assertthat_0.2.1     cachem_1.0.4         openxlsx_4.2.3       xfun_0.22            mime_0.10           
 [99] xtable_1.8-4         broom_0.7.6          later_1.1.0.1        rstatix_0.7.0        viridisLite_0.4.0    tibble_3.1.1         AnnotationDbi_1.50.3 memoise_2.0.0        IRanges_2.22.2       cluster_2.1.2        ellipsis_0.3.1      
LS0tCnRpdGxlOiAiTWluaS1wcm9qZXQgMjAyMSAtIEV4cGxvcmF0aW9uIGRlcyBkb25uw6llcyBkZSBQYXZrb3ZpYyIKYXV0aG9yOiAiUHLDqW5vbSBOb20iCmRhdGU6ICdgciBTeXMuRGF0ZSgpYCcKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBzZWxmX2NvbnRhaW5lZDogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4KICAgIHRoZW1lOiBjZXJ1bGVhbgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogImhpZGUiCiAgcGRmX2RvY3VtZW50OgogICAgZmlnX2NhcHRpb246IHllcwogICAgaGlnaGxpZ2h0OiB6ZW5idXJuCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQotLS0KCgpgYGB7ciBzZXR0aW5ncywgaW5jbHVkZT1GQUxTRSwgZWNobz1GQUxTRSwgZXZhbD1UUlVFfQpvcHRpb25zKHdpZHRoID0gMzAwKQojIG9wdGlvbnMoZW5jb2RpbmcgPSAnVVRGLTgnKQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDUsIAogIGZpZy5wYXRoID0gJ2ZpZ3VyZXMvbWluaS1wcm9qZXRfJywKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgCiAgc2l6ZSA9ICJ0aW55IiwgCiAgZWNobyA9IFRSVUUsIAogIGV2YWwgPSBUUlVFLCAKICB3YXJuaW5nID0gRkFMU0UsIAogIG1lc3NhZ2UgPSBGQUxTRSwgCiAgcmVzdWx0cyA9IFRSVUUsIAogIGNvbW1lbnQgPSAiIikKCm9wdGlvbnMoc2NpcGVuID0gMTIpICMjIE1heCBudW1iZXIgb2YgZGlnaXRzIGZvciBub24tc2NpZW50aWZpYyBub3RhdGlvbgojIGtuaXRyOjphc2lzX291dHB1dCgiXFxmb290bm90ZXNpemUiKQpgYGAKCmBgYHtyIGxpYnJhcmllcywgZWNobz1GQUxTRSwgZXZhbD1UUlVFfQojIyMjIFJlcXVpcmVkIGxpYnJhcmllcyAjIyMjCgojIExvYWQgcmVxdWlyZWQgQ1JBTiBSIGxpYnJhcmllcwpyZXF1aXJlZF9jcmFuTGliIDwtIGMoImtuaXRyIiwgCiAgICAgICAgICAgICAgICAgICAgICAiRmFjdG9NaW5lUiIsIAogICAgICAgICAgICAgICAgICAgICAgImZhY3RvZXh0cmEiLCAKICAgICAgICAgICAgICAgICAgICAgICJncHJvZmlsZXIyIiwKICAgICAgICAgICAgICAgICAgICAgICJwaGVhdG1hcCIpCmZvciAobGliIGluIHJlcXVpcmVkX2NyYW5MaWIpIHsKICBpZiAoIXJlcXVpcmUobGliLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7CiAgICBpbnN0YWxsLnBhY2thZ2VzKGxpYikKICB9CiAgcmVxdWlyZShsaWIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKfQoKcmVxdWlyZWRfYmlvY0xpYiA8LSBjKCJiaW9tYVJ0IikKZm9yIChsaWIgaW4gcmVxdWlyZWRfYmlvY0xpYikgewogIGlmICghcmVxdWlyZShsaWIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKGxpYikKICB9CiAgcmVxdWlyZShsaWIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKfQoKa2FibGUoYXMuZGF0YS5mcmFtZShjKHJlcXVpcmVkX2NyYW5MaWIsIHJlcXVpcmVkX2Jpb2NMaWIpKSwKICAgICAgY29sLm5hbWVzID0gImxpYnJhcmllcyIsCiAgICAgIGNhcHRpb24gPSAiTG9hZGVkIHJlcXVpcmVkIGxpYnJhcmllcyIKICAgICkKCmBgYAoKIyMgU3lub3BzaXMgZHUgcHJvamV0CgojIyMgVHJhdmFpbCBkZW1hbmTDqQoKTGUgYnV0IGRlIGNlIHRyYXZhaWwgZXN0IGRlIG1ldHRyZSBlbiBvZXV2cmUgbGVzIG3DqXRob2RlcyB2dWVzIGRhbnMgbGUgbW9kdWxlIDMgIlIgZXQgc3RhdGlzdGlxdWVzIiBwb3VyIGV4cGxvcmVyIGxlIGpldSBkZSBkb25uw6llcyBkZSBQYXZrb3ZpYywgZXQgZGUgcmVuZHJlIHVuIHJhcHBvcnQgZCdhbmFseXNlIGF1IGZvcm1hdCBgLlJtZGAuIAoKTm91cyBmb3Vybmlzc29ucyBjaS1kZXNzb3VzIHVuZSB0cmFtZSBhdmVjIGxlcyBwcmluY2lwYWxlcyBzZWN0aW9ucyBhdHRlbmR1ZXMuIENlcnRhaW5lcyBjb250aWVubmVudCBkw6lqw6AgZHUgY29kZS4gVm91cyBkZXZyZXogZW4gY29tcGzDqXRlciBkJ2F1dHJlcy4gU2VudGV6LXZvdXMgbGlicmVzIGQnYWRhcHRlciBjZXR0ZSB0cmFtZSBvdSBkJ3kgYWpvdXRlciBkZXMgYW5hbHlzZXMgY29tcGzDqW1lbnRhaXJlcyBzaSBlbGxlcyB2b3VzIGFpZGVudCDDoCBpbnRlcnByw6l0ZXIgdm9zIHLDqXN1bHRhdHMuIAoKIyMjIFJlbWlzZSBkdSByYXBwb3J0CgpEYXRlOiAqKmxlIDE3IG1haSAyMDIxIG1pbnVpdCoqLiAgU2kgdm91cyBhbnRpY2lwZXogdW4gcHJvYmzDqG1lIHBvdXIgcmVtZXR0cmUgbGUgcmFwcG9ydCDDoCBjZXR0ZSBkYXRlIGNvbnRhY3Rlei1ub3VzIGF1c3NpIHJhcGlkZW1lbnQgcXVlIHBvc3NpYmxlIHBvdXIgcXVlIG5vdXMgcHVpc3Npb25zIHByw6l2b2lyIHVuZSByZW1pc2UgcGx1cyB0YXJkaXZlLiAKCi0gQ29tbWVuY2V6IHBhciByZW5vbW1lciBsZSBmaWNoaWVyIC5SbWQgZW4gcmVtcGxhw6dhbnQgUHJlbm9tLU5PTSBwYXIgdm9zIG5vbSBldCBwcsOpbm9tLiAKLSBMZSByYXBwb3J0IGVzdCBhdHRlbmR1IGVuIGZvcm1hdHMgLlJtZCArIC5IVE1MIChlbiBnYXJkYW50IGwnb3B0aW9uIHNlbGZfY29udGFpbmVkIGRlIGwnZW4tdMOqdGUgYWN0aXbDqWUpLiAKLSBEw6lwb3NleiBsZXMgZmljaGllcnMgZGFucyB1biBzb3VzLWRvc3NpZXIgZGUgdm90ZSBjb21wdGUgZHUgY2x1c3Rlci4gQXR0ZW50aW9uLCB2ZWlsbGV6IMOgIHJlc3BlY3RlciBwcsOpY2lzw6ltZW50IGNldHRlIHN0cnVjdHVyZSBkZSBjaGVtaW4gY2FyIG5vdXMgbm91cyBiYXNlcm9ucyBkZXNzdXMgcG91ciByw6ljdXDDqXJlciB2b3MgcsOpc3VsdGF0cy4gCgogICAgYC9zaGFyZWQvcHJvamVjdHMvZHViaWkyMDIxL1tsb2dpbl0vbTMtc3RhdC1SL21pbmktcHJvamV0YCAKCiMjIyBDcml0w6hyZXMgZCfDqXZhbHVhdGlvbgoKLSBSZXByb2R1Y3RpYmlsaXTDqSBkZXMgYW5hbHlzZXM6IG5vdXMgdGVudGVyb25zIGRlIHJlZ8OpbsOpcmVyIGxlIHJhcHBvcnQgSFRNTCDDoCBwYXJ0aXIgZGUgdm90cmUgUm1kLCBlbiBwYXJ0YW50IGRlIG5vdHJlIGNvbXB0ZSBzdXIgbGUgc2VydmV1ciBJRkIuIAotIE1hbmlwdWxhdGlvbiBkZXMgb2JqZXRzIFIKLSBNb2JpbGlzYXRpb24gZGVzIG3DqXRob2RlcyBzdGF0aXN0aXF1ZXMgdnVlcyBhdSBjb3VycwotIFBlcnRpbmVuY2UgZGVzIGludGVycHLDqXRhdGlvbnMgc3RhdGlzdGlxdWVzCi0gUGVydGluZW5jZSBkZXMgaW50ZXJwcsOpdGF0aW9ucyBiaW9sb2dpcXVlcwotIENsYXJ0w6kgZGUgbGEgcsOpZGFjdGlvbgotIENsYXJ0w6kgZGVzIGlsbHVzdHJhdGlvbnMgKGZpZ3VyZXMgZXQgdGFibGVhdXgpOiBncmFwaGlzbWVzLCBsw6lnZW5kZXMgLi4uCgpOb3VzIHZvdXMgZW5jb3VyYWdlb25zIMOgIGFzc3VyZXIgbGEgbGlzaWJpbGl0w6kgZGUgdm90cmUgY29kZSAoc3ludGF4ZSwgbm9tbWFnZSBkZXMgdmFyaWFibGVzLCBjb21tZW50YWlyZXMgZGUgY29kZSkKCiMjIyBPYmplY3RpZnMgc2NpZW50aWZpcXVlcwoKTm91cyBwYXJ0b25zIGR1IG3Dqm1lIGpldSBkZSBkb25uw6llcyAqRmlsIFJvdWdlKiBkZSBjZSBtb2R1bGUgaXNzdWVzIGRlIGxhIHB1YmxpY2F0aW9uIFBhdmtvdmljLCBNLiwgUGFudGFubywgTC4sIEdlcmxhY2gsIEMuVi4gZXQgYWwuIE11bHRpIG9taWNzIGFuYWx5c2lzIG9mIGZpYnJvdGljIGtpZG5leXMgaW4gdHdvIG1vdXNlIG1vZGVscy4gU2NpIERhdGEgNiwgOTIgKDIwMTkpLiBodHRwczovL2RvaS5vcmcvMTAuMTAzOC9zNDE1OTctMDE5LTAwOTUtNQoKKipSYXBwZWwgc3VyIGxlcyDDqWNoYW50aWxsb25zOioqCgpEZXV4IG1vZMOobGVzIGRlIGZpYnJvc2UgcsOpbmFsZSBjaGV6IGxhIHNvdXJpcyBzb250IMOpdHVkacOpczoKCjEuIExlIHByZW1pZXIgZXN0IHVuIG1vZMOobGUgZGUgbsOpcGhyb3BhdGhpZSByw6l2ZXJzaWJsZSBpbmR1aXRlIHBhciBsJ2FjaWRlIGZvbGlxdWUgKGZvbGljIGFjaWQgKEZBKSkuIExlcyBzb3VyaXMgb250IMOpdMOpIHNhY3JpZmnDqWVzIGF2YW50IGxlIHRyYWl0ZW1lbnQgKG5vcm1hbCksIHB1aXMgw6Agam91ciAxLCAyLCA3IGV0IDE0IChkYXkxLC4uLikgYXByw6hzIHVuZSBzZXVsZSBpbmplY3Rpb24gZCdhY2lkZSBmb2xpcXVlLgoKMi4gTGUgc2Vjb25kIGVzdCB1biBtb2TDqGxlIGlycsOpdmVyc2libGUgaW5kdWl0IGNocmlydXJnaWNhbGVtZW50ICh1bmlsYXRlcmFsIHVyZXRlcmFsIG9ic3RydWN0aW9uIChVVU8pKS4gbGVzIHNvdXJpcyBvbnQgw6l0w6kgc2FjcmlmacOpZXMgYXZhbnQgb2JzdHJ1Y3Rpb24gKGRheSAwKSBldCDDoCAzLCA3IGV0IDE0IGpvdXJzIGFwcsOocyBvYnN0cnVjdGlvbiBwYXIgbGlnYXRpb24gZGUgbCd1cmV0w6hyZSBkdSByZWluIGdhdWNoZS4KCkEgcGFydGlyIGRlIGNlcyBleHRyYWl0cyBkZSByZWluLCBsJ0FSTiBtZXNzYWdlciB0b3RhbCBldCBsZXMgcGV0aXRzIEFSTnMgb250IMOpdMOpIHPDqXF1ZW5jw6lzIGV0IGxlcyBwcm90w6lpbmVzIGNhcmF0w6lyaXPDqWVzIHBhciBzcGVjdHJvbcOpdHJpZSBkZSBtYXNzZSBlbiB0YW5kZW0gKFRNVCkuCgoqKkJ1dCBzY2llbnRpZmlxdWU6KiogRGFucyBsZSB0dXRvcmllbCBzdXIgbGVzIGRhdGFmcmFtZXMsIHZvdXMgYXZleiB0cmF2YWlsbMOpIHN1ciBsZXMgZG9ubsOpZXMgZGUgKioqdHJhbnNjcmlwdG9tZSBkdSBtb2TDqGxlIFVVTyoqKi4gRGFucyBjZSBtaW5pLXByb2pldCwgdm91cyBhbGxleiB0cmF2YWlsbGVyIHN1ciBsZXMgZG9ubsOpZXMgZHUgKioqdHJhbnNjcmlwdG9tZSBkdSBtb2TDqGxlIEZBKioqIGFmaW4gZGUgcmVncm91cGVyIGxlcyBvYnNlcnZhdGlvbnMgKMOpY2hhbnRpbGxvbikgZXQgbGVzIGfDqG5lcyBzZWxvbiBkZXMgcHJvZmlscyBkJ2V4cHJlc3Npb24gc2ltaWxhaXJlcy4KCioqVm90cmUgcHJvamV0IHNlIGTDqWNvbXBvc2UgZW4gNSBwYXJ0aWVzIGRvbnQgMyBzZXJvbnQgw6AgcsOpYWxpc2VyIHBhcjoqKgoKMS4gU3RhdGl0aXF1ZXMgZGVzY3JpcHRpdmVzIGRlcyBkb25uw6llcyBicnV0ZXM6IGNvbW1hbmRlcyBmb3VybmllcwoyLiBOb3JtYWxpc2F0aW9uIGRlcyBkb25uw6llcyA6IGNvbW1hbmRlcyBmb3VybmllcwozLiBTdGF0aXN0aXF1ZXMgZGVzY3JpcHRpdmVzIGRlcyBkb25uw6llcyBub3JtYWxpc8OpZXM6IMOgIHZvdXMgZGUgam91ZXIKNC4gQW5hbHlzZSBkZSByZWdyb3VwZW1lbnQgZGVzIGRvbm7DqWVzOiDDoCB2b3VzIGRlIGpvdWVyCjUuIEFuYWx5c2UgZCdlbnJpY2hpc3NlbWVudCBmb25jdGlvbm5lbDogw6Agdm91cyBkZSBqb3VlcgoKIyMgMS4gTGVzIGRvbm7DqWVzIGJydXRlcwoKKioqVm91cyBuJ2F2ZXogcmllbiDDoCBjb2RlciBpY2kuIExlIGNvZGUgZXN0IGZvdXJuaS4qKioKCiMjIyBDaGFyZ2VtZW50IGRlcyBkb25uw6llcyBicnV0ZXMKCkxlIGJsb2Mgc3VpdmFudCBjb250aWVudCB1bmUgZm9uY3Rpb24gcXVpIHBlcm1ldCBkZSB0w6lsw6ljaGFyZ2VyIHVuIGZpY2hpZXIgZGFucyBsJ2VzcGFjZSBkZSB0cmF2YWlsLCBzYXVmIHMnaWwgZXN0IGTDqWrDoCBwcsOpc2VudC4gTm91cyBsJ3V0aWxpc2Vyb25zIGVuc3VpdGUgcG91ciB0w6lsw6ljaGFyZ2VyIGxlcyBkb25uw6llcyDDoCBhbmFseXNlciBlbiDDqXZpdGFudCBkZSByZWZhaXJlIGxlIHRyYW5zZmVydCDDoCBjaGFxdWUgZXjDqWN1dGlvbiBkZSBsJ2FuYWx5c2UuIAoKYGBge3IgZnVuY3Rpb25fZG93bmxvYWRfb25seV9vbmNlfQojJyBAdGl0bGUgRG93bmxvYWQgYSBmaWxlIG9ubHkgaWYgaXQgaXMgbm90IHlldCBoZXJlCiMnIEBhdXRob3IgSmFjcXVlcyB2YW4gSGVsZGVuIGVtYWlse0phY3F1ZXMudmFuLUhlbGRlbkBAZnJhbmNlLWJpb2luZm9ybWF0aXF1ZS5mcn0KIycgQHBhcmFtIHVybF9iYXNlIGJhc2Ugb2YgdGhlIFVSTCwgdGhhdCB3aWxsIGJlIHByZXBlbmRlZCB0byB0aGUgZmlsZSBuYW1lCiMnIEBwYXJhbSBmaWxlX25hbWUgbmFtZSBvZiB0aGUgZmlsZSAoc2hvdWxkIG5vdCBjb250YWluIGFueSBwYXRoKQojJyBAcGFyYW0gbG9jYWxfZm9sZGVyIHBhdGggb2YgYSBsb2NhbCBmb2xkZXIgd2hlcmUgdGhlIGZpbGUgc2hvdWxkIGJlIHN0b3JlZAojJyBAcmV0dXJuIHRoZSBmdW5jdGlvbiByZXR1cm5zIHRoZSBwYXRoIG9mIHRoZSBsb2NhbCBmaWxlLCBidWlsdCBmcm9tIGxvY2FsX2ZvbGRlciBhbmQgZmlsZV9uYW1lCiMnIEBleHBvcnTCqQpkb3dubG9hZF9vbmx5X29uY2UgPC0gZnVuY3Rpb24oCiAgdXJsX2Jhc2UsIAogIGZpbGVfbmFtZSwKICBsb2NhbF9mb2xkZXIpIHsKCiAgIyMgRGVmaW5lIHRoZSBzb3VyY2UgVVJMICAKICB1cmwgPC0gZmlsZS5wYXRoKHVybF9iYXNlLCBmaWxlX25hbWUpCiAgbWVzc2FnZSgiU291cmNlIFVSTFxuXHQiLCAgdXJsKQoKICAjIyBEZWZpbmUgdGhlIGxvY2FsIGZpbGUKICBsb2NhbF9maWxlIDwtIGZpbGUucGF0aChsb2NhbF9mb2xkZXIsIGZpbGVfbmFtZSkKICAKICAjIyBDcmVhdGUgdGhlIGxvY2FsIGRhdGEgZm9sZGVyIGlmIGl0IGRvZXMgbm90IGV4aXN0CiAgZGlyLmNyZWF0ZShsb2NhbF9mb2xkZXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFLCByZWN1cnNpdmUgPSBUUlVFKQogIAogICMjIERvd25sb2FkIHRoZSBmaWxlIE9OTFkgaWYgaXQgaXMgbm90IGFscmVhZHkgdGhlcmUKICBpZiAoIWZpbGUuZXhpc3RzKGxvY2FsX2ZpbGUpKSB7CiAgICBtZXNzYWdlKCJEb3dubG9hZGluZyBmaWxlIGZyb20gc291cmNlIFVSTCB0byBsb2NhbCBmaWxlXG5cdCIsIAogICAgICAgICAgICBsb2NhbF9maWxlKQogICAgZG93bmxvYWQuZmlsZSh1cmwgPSB1cmwsIGRlc3RmaWxlID0gbG9jYWxfZmlsZSkKICB9IGVsc2UgewogICAgbWVzc2FnZSgiTG9jYWwgZmlsZSBhbHJlYWR5IGV4aXN0cywgbm8gbmVlZCB0byBkb3dubG9hZFxuXHQiLCAKICAgICAgICAgICAgbG9jYWxfZmlsZSkKICB9CiAgCiAgcmV0dXJuKGxvY2FsX2ZpbGUpCn0KYGBgCgpOb3VzIHTDqWzDqWNoYXJnZW9ucyBkZXV4IGZpY2hpZXJzIGRhbnMgdW4gZG9zc2llciBsb2NhbCBgfi9tMy1zdGF0LVIvcGF2a292aWNfYW5hbHlzaXNgICoqKHZvdXMgcG91dmV6IGNoYW5nZXIgbGUgbm9tIG91IGNoZW1pbiBkYW5zIGxlIGNodW5rIGNpLWRlc3NvdXMpKiosIGV0IGxlcyBjaGFyZ2VvbnMgZGFucyBsZXMgZGF0YS5mcmFtZXMgc3VpdmFudHM6IAoKLSBEb25uw6llcyBicnV0ZXMgZGUgdHJhbnNjcmlwdG9tZTogYGZhX2V4cHJfcmF3YAotIE3DqXRhZG9ubsOpZXM6IGBmYV9tZXRhYAoKYGBge3IgZG93bmxvYWRfYW5kX2xvYWR9CiMjIERlZmluZSB0aGUgcmVtb3RlIFVSTCBhbmQgbG9jYWwgZm9sZGVyCnBhdmtvdmljX3VybCA8LSAiaHR0cHM6Ly9naXRodWIuY29tL0RVLUJpaS9tb2R1bGUtMy1TdGF0LVIvcmF3L21hc3Rlci9zdGF0LVJfMjAyMS9kYXRhL3BhdmtvdmljXzIwMTkvIgoKIyMgRGVmaW5lIHRoZSBsb2NhbCBmb2xkZXIgZm9yIHRoaXMgYW5hbHlzaXMgKHdoZXJlIHRoZSBkYXRhIHdpbGwgYmUgZG93bmxvYWRlZCBhbmQgdGhlIHJlc3VsdHMgZ2VuZXJhdGVkKQpwYXZrb3ZpY19mb2xkZXIgPC0gIn4vbTMtc3RhdC1SL3BhdmtvdmljX2FuYWx5c2lzIgoKIyMgRGVmaW5lIGEgc3ViLWZvbGRlciBmb3IgdGhlIGRhdGEKcGF2a292aWNfZGF0YV9mb2xkZXIgPC0gZmlsZS5wYXRoKHBhdmtvdmljX2ZvbGRlciwgImRhdGEiKQoKIyMgRG93bmxvYWQgYW5kIGxvYWQgdGhlIGV4cHJlc3Npb24gZGF0YSB0YWJsZQojIyBOb3RlOiB3ZSB1c2UgY2hlY2submFtZXM9RkFMU0UgdG8gYXZvaWQgcmVwbGFjaW5nIGh5cGhlbnMgYnkgZG90cwojIyBpbiBzYW1wbGUgbmFtZXMsIGJlY2F1c2Ugd2Ugd2FudCB0byBrZWVwIHRoZW0gYXMgaW4gdGhlIAojIyBvcmlnaW5hbCBkYXRhIGZpbGVzLiAKbWVzc2FnZSgiRG93bmxvYWRpbmcgRkEgdHJhbnNjcmlwdG9tZSBmaWxlXHQiLCAiZmFfcmF3X2NvdW50cy50c3YuZ3oiLAogICJcblx0ZnJvbVx0IiwgcGF2a292aWNfdXJsKQpmYV9leHByX2ZpbGUgPC0gZG93bmxvYWRfb25seV9vbmNlKAogIHVybF9iYXNlID0gcGF2a292aWNfdXJsLCAKICBmaWxlX25hbWUgPSAiZmFfcmF3X2NvdW50cy50c3YuZ3oiLAogIGxvY2FsX2ZvbGRlciA9IHBhdmtvdmljX2RhdGFfZm9sZGVyKQoKIyMgTG9hZCB0aGUgZXhwcmVzZHNpb24gdGFibGUKbWVzc2FnZSgiTG9hZGluZyBGQSB0cmFuc2NyaXB0b21lIGRhdGEgZnJvbVxuXHQiLCBmYV9leHByX2ZpbGUpCmZhX2V4cHJfcmF3IDwtIHJlYWQuZGVsaW0oZmlsZSA9IGZhX2V4cHJfZmlsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSkKCiMjIERvd25sb2FkIHRoZSBtZXRhZGF0YSBmaWxlCm1lc3NhZ2UoIkRvd25sb2FkaW5nIEZBIG1ldGFkYXRhIGZpbGVcdCIsICJmYV90cmFuc2NyaXB0b21lX21ldGFkYXRhLnRzdiIsCiAgIlxuXHRmcm9tXHQiLCBwYXZrb3ZpY191cmwpCmZhX21ldGFfZmlsZSA8LSBkb3dubG9hZF9vbmx5X29uY2UoCiAgdXJsX2Jhc2UgPSBwYXZrb3ZpY191cmwsIAogIGZpbGVfbmFtZSA9ICJmYV90cmFuc2NyaXB0b21lX21ldGFkYXRhLnRzdiIsCiAgbG9jYWxfZm9sZGVyID0gcGF2a292aWNfZGF0YV9mb2xkZXIpCgojIyBMb2FkIHRoZSBtZXRhZGF0YQptZXNzYWdlKCJMb2FkaW5nIEZBIG1ldGFkYXRhIGZyb21cblx0IiwgZmFfbWV0YV9maWxlKQpmYV9tZXRhIDwtIHJlYWQuZGVsaW0oZmlsZSA9IGZhX21ldGFfZmlsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSkKYGBgCgpOb3VzIHJlZ2FyZG9ucyBsYSBzdHJ1Y3R1cmUgZGUgY2hhcXVlIGRhdGFmcmFtZS4KCmBgYHtyIGluc2VwY3QgZGF0YX0Kc3RyKGZhX2V4cHJfcmF3KQpzdHIoZmFfbWV0YSkKYGBgCgpMZXMgZGV1eCBmaWNoaWVycyBuZSBkb25uZW50IHBhcyBsZXMgb2JzZXJ2YXRpb25zIGRlIGwnw6ljaGFudGlsbG9uIGRhbnMgbGUgbcOqbWUgb3JkcmU6CgpgYGB7ciBjaGVjayBkYXRhIG9yZGVyfQpmYV9tZXRhJHNhbXBsZU5hbWUgPT0gbmFtZXMoZmFfZXhwcl9yYXcpCmBgYAoKTm91cyBsZXMgcsOpb3JnYW5pc29ucyBsZXMgw6ljaGFudGlsbG9ucyBkYW5zIGwnb3JkcmUgZGUgbCdleHDDqXJpZW5jZTogY29uZGl0aW9uIG5vcm1hbGUsIHB1aXMgZGF5IDEgw6AgMTQgYXZlYyBsZXMgMyByw6lwbGljYXRzLgoKYGBge3IgcmVvZGVyIGRhdGF9CnNhbXBsZV9vcmRlciA8LSBjKHBhc3RlKHJlcChjKCJub3JtYWwiLCAiZGF5MSIsICJkYXkyIiwgImRheTMiLCAiZGF5NyIsICJkYXkxNCIpLCBlYWNoID0gMyksCiAgICAgICAgICAgICAgICAgICAgICAgIDE6Mywgc2VwID0gIl8iKSkKCmZhX2V4cHJfcmF3IDwtIGZhX2V4cHJfcmF3WyxzYW1wbGVfb3JkZXJdCmZhX21ldGEgPC0gZmFfbWV0YVttYXRjaChzYW1wbGVfb3JkZXIsIGZhX21ldGEkc2FtcGxlTmFtZSksXQoKIyBWaWV3KGZhX21ldGEpCmthYmxlKGZhX21ldGEsIGNhcHRpb24gPSAiTWV0ZGF0YSBmb3IgUGF2a292b2MgRkEgdHJhbnNjcmlwdG9tZSIpCmBgYAoKPT4gQWluc2ksIG5vdXMgYXZvbnMgdW4gamV1IGRlIGRvbm7DqWVzIGF2ZWMgdW4gw6ljaGFudGlsbG9uIGRlIGByIG5yb3coZmFfbWV0YSlgIG9ic2VydmF0aW9ucyBldCBkZXMgZG9ubsOpZXMgZCdleHByZXNzaW9uIGRlIGByIG5yb3coZmFfZXhwcl9yYXcpYCBnw6huZXMuCgoKIyMjIFN0YXRpc3RpcXVlcyBkZXNjcmlwdGl2ZXMKCkRhbnMgbGUgdHV0b3JpYWwgc3VyIGxlcyBkYXRhZnJhbWVzIHN1ciBsZSBqZXUgZGUgZG9ubsOpZXMgInV1byIgKHJlbGlzZXogbGUgY29ycmlnw6kpLCBub3VzIHZvdXMgYXZvbnMgZGVtYW5kw6kgZGUgY3LDqWVyIHVuIGRhdGEuZnJhbWUgcXVpIGNvbGxlY3RlIGxlcyBzdGF0aXN0aXF1ZXMgcGFyIGfDqG5lIGV0IHBhciDDqWNoYW50aWxsb24uIE5vdXMgdm91cyBkZW1hbmRvbnMgZGUgcsOpYWxpc2VyIHVuZSDDqXR1ZGUgc2ltaWxhaXJlIHN1ciBsZXMgZG9ubsOpZXMgIkZBIiBhdmFudCBldCBhcHLDqHMgbm9ybWFsaXNhdGlvbiBpbnRlci3DqWNoYW50aWxsb25zIGRlcyBkb25uw6llcy4gTGUgY29kZSBkZSBsYSBwYXJ0aWUgYXZhbnQgbm9ybWFsaXNhdGlvbiBlc3QgZG9ubsOpLgoKIyMjIyBQYXIgw6ljaGFudGlsbG9uIGF2YW50IG5vcm1hbGlzYXRpb24KCk5vdXMgY3LDqW9ucyB1biBkYXRhLmZyYW1lIG5vbW3DqSBgc2FtcGxlX3N0YXRfcHJlbm9ybWAgcXVpIGNvbXBvcnRlIHVuZSBsaWduZSBwYXIgw6ljaGFudGlsbG9uIGV0IHVuZSBjb2xvbm5lIHBhciBzdGF0aXN0aXF1ZS4gTm91cyBjYWxjdWxvbnMgbGVzIHN0YXRpc3RpcXVlcyBzdWl2YW50ZXMgc3VyIGxlcyB2YWxldXJzIGxvZzIgZCdleHByZXNzaW9uIGRlIGNoYXF1ZSDDqWNoYW50aWxsb246CgotIG1veWVubmUKLSDDqWNhcnQtdHlwZQotIGludGVydmFsbGUgaW50ZXItcXVhcnRpbGVzCi0gcHJlbWllciBxdWFydGlsZQotIG3DqWRpYW5lCi0gdHJvaXNpw6htZSBxdWFydGlsZQotIG1heGltdW0KLSBub21icmUgZGUgdmFsZXVycyBudWxsZXMKCklsIGVzdCBhZmZpY2jDqSBhdmVjIGxhIGZvbmN0aW9uIGBrYWJsZSgpYC4gCgpgYGB7ciBzYW1wbGVfc3RhdF9wcmVfbm9ybX0KbWVzc2FnZSgiQ29tcHV0aW5nIHNhbXBsZS13aXNlIHN0YXRpc3RpY3Mgb24gcmF3IGNvdW50cyIpCnNhbXBsZV9zdGF0X3ByZW5vcm0gPC0gZGF0YS5mcmFtZSgKICBtZWFuID0gYXBwbHkoZmFfZXhwcl9yYXcsIDIsIG1lYW4sIG5hLnJtID0gVFJVRSksCiAgc2QgPSBhcHBseShmYV9leHByX3JhdywgMiwgc2QsIG5hLnJtID0gVFJVRSksCiAgaXFyID0gYXBwbHkoZmFfZXhwcl9yYXcsIDIsIElRUiwgbmEucm0gPSBUUlVFKSwKICBRMSA9IGFwcGx5KGZhX2V4cHJfcmF3LCAyLCBxdWFudGlsZSwgcCA9IDAuMjUsIG5hLnJtID0gVFJVRSksCiAgbWVkaWFuID0gYXBwbHkoZmFfZXhwcl9yYXcsIDIsIG1lZGlhbiwgbmEucm0gPSBUUlVFKSwKICBRMyA9IGFwcGx5KGZhX2V4cHJfcmF3LCAyLCBxdWFudGlsZSwgcCA9IDAuNzUsIG5hLnJtID0gVFJVRSksCiAgbWF4ID0gYXBwbHkoZmFfZXhwcl9yYXcsIDIsIG1heCwgbmEucm0gPSBUUlVFKSwKICBudWxsID0gYXBwbHkoZmFfZXhwcl9yYXcgPT0gMCwgMiwgc3VtLCBuYS5ybSA9IFRSVUUpCikKCmthYmxlKHNhbXBsZV9zdGF0X3ByZW5vcm0sIGNhcHRpb24gPSAiU2FtcGxlLXdpc2Ugc3RhdGlzdGljcyBiZWZvcmUgbm9ybWFsaXNhdGlvbi4iKQpgYGAKCiMjIyMgUGFyIGfDqG5lIGF2YW50IG5vcm1hbGlzYXRpb24KCk5vdXMgY3LDqW9ucyBjaS1kZXNzb3VzIHVuIGRhdGEuZnJhbWUgbm9tbcOpIGBnZW5lX3N0YXRfcHJlbm9ybWAgcXVpIGNvbXBvcnRlIHVuZSBsaWduZSBwYXIgZ8OobmUgZXQgdW5lIGNvbG9ubmUgcGFyIHN0YXRpc3RpcXVlLiBOb3VzIGNhbGN1bG9ucyBsZXMgc3RhdGlzdGlxdWVzIHN1aXZhbnRlcyBzdXIgbGVzIHZhbGV1cnMgbG9nMiBkZSBjaGFxdWUgZ8OobmUuCgotIG1veWVubmUKLSBtw6lkaWFuZQotIMOpY2FydC10eXBlCi0gcHJlbWllciBxdWFydGlsZQotIHRyb2lzacOobWUgcXVhcnRpbGUKLSBtYXhpbXVtCi0gbm9tYnJlIGRlIHZhbGV1cnMgbnVsbGVzCi0gaW50ZXJ2YWxsZSBpbnRlci1xdWFydGlsZXMKCkNlcyByw6lzdWx0YXRzIHNvbnQgc3RvY2vDqXMgZGFucyB1biBkYXRhLmZyYW1lIGF2ZWMgMSBsaWduZSBwYXIgw6ljaGFudGlsbG9uIGV0IDEgY29sb25uZSBwYXIgc3RhdGlzdGlxdWUuIE5vdXMgYWZmaWNob25zIGxlcyBsaWduZXMgMTAwIMOgIDEwOSBkZSBjZSB0YWJsZWF1IGRlIHN0YXRpc3RpcXVlcyBhdmVjIGxhIGZvbmN0aW9uIGBrYWJsZSgpYC4KCmBgYHtyIGdlbmVfc3RhdF9wcmVfbm9ybX0KIyMgR2VuZS13aXNlIHN0YXRpc3RpY3MgZm9yIHRoZSByYXcgY291bnRzICh3aWxsIGJlIHVzZWQgZm9yIG5vcm1hbGlzYXRpb24pCm1lc3NhZ2UoIkNvbXB1dGluZyBnZW5lLXdpc2Ugc3RhdGlzdGljcyBvbiByYXcgY291bnRzIikKZ2VuZV9zdGF0X3ByZW5vcm0gPC0gZGF0YS5mcmFtZSgKICBtZWFuID0gYXBwbHkoZmFfZXhwcl9yYXcsIDEsIG1lYW4sIG5hLnJtID0gVFJVRSksCiAgc2QgPSBhcHBseShmYV9leHByX3JhdywgMSwgc2QsIG5hLnJtID0gVFJVRSksCiAgaXFyID0gYXBwbHkoZmFfZXhwcl9yYXcsIDEsIElRUiwgbmEucm0gPSBUUlVFKSwKICBRMSA9IGFwcGx5KGZhX2V4cHJfcmF3LCAxLCBxdWFudGlsZSwgcCA9IDAuMjUsIG5hLnJtID0gVFJVRSksCiAgbWVkaWFuID0gYXBwbHkoZmFfZXhwcl9yYXcsIDEsIG1lZGlhbiwgbmEucm0gPSBUUlVFKSwKICBRMyA9IGFwcGx5KGZhX2V4cHJfcmF3LCAxLCBxdWFudGlsZSwgcCA9IDAuNzUsIG5hLnJtID0gVFJVRSksCiAgbWF4ID0gYXBwbHkoZmFfZXhwcl9yYXcsIDEsIG1heCwgbmEucm0gPSBUUlVFKSwKICBudWxsID0gYXBwbHkoZmFfZXhwcl9yYXcgPT0gMCwgMSwgc3VtLCBuYS5ybSA9IFRSVUUpCikKCmthYmxlKGdlbmVfc3RhdF9wcmVub3JtWzEwMDoxMDksIF0sIGNhcHRpb24gPSAiR2VuZS13aXNlIHN0YXRpc3RpY3MgYmVmb3JlIG5vcm1hbGlzYXRpb24iKQpgYGAKCiMjIDIuIEZpbHRyYWdlIGV0IG5vcm1hbGlzYXRpb24gZGVzIGRvbm7DqWVzCgoqKipWb3VzIG4nYXZleiByaWVuIMOgIGNvZGVyIGljaS4gTGUgY29kZSBlc3QgZm91cm5pLioqKgoKSWwgZXhpc3RlIHBsdXNpZXVycyBmYcOnb25zIGRlIG5vcm1hbGlzZXIgbGVzIGRvbm7DqWVzIGRlIHRyYW5zY3JpcHRvbWUgIHZ1ZXMgZGFucyBsZXMgbW9kdWxlcyA0IGV0IDUgKGNmLiB0b3RhbCBjb3VudHMsIHF1YW50aWxlcywgVE1NLCBSTEUsIGxpbW1hIHZvb20sLi4uKSwgbWFpcyBub3VzIGF2b25zIGNob2lzaSBpY2kgdW5lIHNvbHV0aW9uIHNpbXBsZSB0b3V0IGVuIMOpdGFudCByb2J1c3RlIHBvdXIgbm9ybWFsaXNlciBsZXMgZG9ubsOpZXMgZW4gc3RhbmRhcmRpc2FudCBsZSAzw6htZSBxdWFudGlsZS4gCgpMYSBtw6l0aG9kZSBjaG9pc2llIGljaSBjb25zaXN0ZSDDoCA6CgoxLiAqKkVjYXJ0ZXIgbGVzIGfDqG5lcyAibm9uLWTDqXRlY3TDqXMiKiosIGMnZXN0LcOgLWRpcmUgY2V1eCBheWFudCBkZXMgdmFsZXVycyBudWxsZXMgZGFucyBhdSBtb2lucyA5MCUgZGVzIMOpY2hhbnRpbGxvbnMuCgoyLiAqKkVjYXJ0ZXIgbGVzIGfDqG5lcyDDoCBwZWluZSBleHByaW3DqXMqKiwgYydlc3Qtw6AtZGlyZSBjZXV4IGF5YW50IHVuZSB2YWxldXIgbW95ZW5uZSA8IDEwIChhcmJpdHJhaXJlbWVudCkuCgozLiAqKlN0YW5kYXJkaXNlciBsZXMgw6ljaGFudGlsbG9ucyAqKnN1ciBsZSAzw6htZSBxdWFydGlsZSBkZXMgZ8OobmVzIHJlc3RhbnRzOiBvbiBkaXZpc2UgbGVzIGNvbXB0YWdlcyBicnV0cyBwYXIgbGUgM8OobWUgcXVhcnRpbGUgZGUgbCfDqWNoYW50aWxsb24gZXQgb24gbXVsdGlwbGllIHBhciBsZSAzw6htZSBxdWFydGlsZSBkZSBsJ2Vuc2VtYmxlIGRlcyDDqWNoYW50aWxsb25zLgoKNC4gKipOb3JtYWxpc2VyIGxlcyBjb21wdGFnZXMqKiAoYXUgc2VucyBwcm9wcmUsIGMnZXN0LcOgLWRpcmUgcmFwcHJvY2hlciBsZXVyIGRpc3RyaWJ1dGlvbiBkZSBsYSBkaXN0cmlidXRpb24gZ2F1c3NpZW5uZSkgcGFyIHVuZSB0cmFuc2Zvcm1hdGlvbiBsb2dhcml0aG1pcXVlIChsb2cyKS4gCgpOb3VzIGZvdXJuaXNzb25zIGNpLWRlc3NvdXMgbGUgY29kZS4KCiMjIyBGaWx0cmFnZSA6IMOpbGltaW5hdGlvbiBkZXMgZ8OobmVzIG5vbiBkw6l0ZWN0w6lzIG91IMOgIHBlaW5lIGV4cHJpbcOpcwoKYGBge3IgZ2VuZV9maWx0ZXJpbmd9CiMjIERhdGEgZmlsdGVyaW5nOiBnZW5lcyBoYXZpbmcgYXQgbGVhc3QgOTAlIG51bGwgdmFsdWVzCm1lc3NhZ2UoIkZpbHRlcmluZyB1bmRldGVjdGVkIGdlbmVzIikKdW5kZXRlY3RlZF9nZW5lcyA8LSBnZW5lX3N0YXRfcHJlbm9ybSRudWxsID49IG5jb2woZmFfZXhwcl9yYXcpICogMC45CnByaW50KHBhc3RlMCgiVW5kZXRlY3RlZCBnZW5lcyAobnVsbCBpbiA+PSA5MCUgc2FtcGxlcyk6ICIsIHN1bSh1bmRldGVjdGVkX2dlbmVzKSkpCgojIyBEYXRhIGZpbHRlcmluZzogZ2VuZXMgaGF2aW5nIGEgbWVhbiBleHByZXNzaW9uIDwgMTAKbWVzc2FnZSgiRmlsdGVyaW5nIGJhcmVseSBleHByZXNzZWQgZ2VuZXMiKQpiYXJlbHlfZXhwcmVzc2VkX2dlbmVzIDwtIGdlbmVfc3RhdF9wcmVub3JtJG1lYW4gPCAxMApwcmludChwYXN0ZTAoIkJhcmVseSBleHByZXNzZWQgZ2VuZXMgKG1lYW4gPCAxMCk6ICIsIHN1bShiYXJlbHlfZXhwcmVzc2VkX2dlbmVzKSkpCgojIyBBcHBseSBmaWx0ZXJpbmcgb24gYm90aCBjcml0ZXJpYQpkaXNjYXJkZWRfZ2VuZXMgPC0gdW5kZXRlY3RlZF9nZW5lcyB8IGJhcmVseV9leHByZXNzZWRfZ2VuZXMKcHJpbnQocGFzdGUwKCJEaXNjYXJkZWQgZ2VuZXM6ICIsIHN1bShkaXNjYXJkZWRfZ2VuZXMpKSkKa2VwdF9nZW5lcyA8LSAhZGlzY2FyZGVkX2dlbmVzCnByaW50KHBhc3RlMCgiS2VwdCBnZW5lczogIiwgc3VtKGtlcHRfZ2VuZXMpKSkKCiMjIEdlbmVzIGFmdGVyIGZpbHRlcmluZwpmYV9leHByX2ZpbHRlcmVkIDwtIGZhX2V4cHJfcmF3W2tlcHRfZ2VuZXMsIF0KCmBgYAoKCgoKPCEtLSAjIyMjIFRNTSB2aWEgZWRnZVIgLS0+Cgo8IS0tIE5vdXMgYXBwbGlxdW9ucyBpY2kgbGEgbm9ybWFsaXNhdGlvbiBzdXIgYmFzZSBkZSBsYSBtw6l0aG9kZSBUTU0gKFRyaW1tZWQgTWVhbiBvZiB0aGUgTS12YWx1ZXMpIGTDqXZlbG9wcMOpZSBwYXIgUm9iaW5zb24gZXQgT3NobGFjay4gIC0tPgoKPCEtLSAtIFJvYmluc29uLCBNLkQuLCBPc2hsYWNrLCBBLiBBIHNjYWxpbmcgbm9ybWFsaXphdGlvbiBtZXRob2QgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIG9mIFJOQS1zZXEgZGF0YS4gR2Vub21lIEJpb2wgMTEsIFIyNSAoMjAxMCkuIDxodHRwczovL2RvaS5vcmcvMTAuMTE4Ni9nYi0yMDEwLTExLTMtcjI1PiAtLT4KCgoKPCEtLSBgYGB7ciB0bW1fc3RhbmRhcmRpc2F0aW9ufSAtLT4KPCEtLSBtZXNzYWdlKCJTdGFuZGFyZGlzaW5nIHRoZSBjb3VudHMgd2lodCBlZGdlUiBUTU0gbWV0aG9kIikgLS0+Cgo8IS0tICMjIENyZWF0ZSBhbiBlZGdlUiBvYmplY3Qgd2l0aCB0aGUgdHJhbnNjcmlwdG9tZSBkYXRhIC0tPgo8IS0tIGQgPC0gREdFTGlzdChjb3VudHMgPSBmYV9leHByX3JhdywgZ3JvdXAgPSBmYV9tZXRhJGNvbmRpdGlvbikgLS0+Cgo8IS0tICMjIENvbXB1dGUgdGhlIG5vcm1hbGlzaW5mZyBmYWN0b3JzIHdpdGggdGhlIFRNTSBtZXRob2QgLS0+CjwhLS0gZCA8LSBjYWxjTm9ybUZhY3RvcnMoZCwgbWV0aG9kID0gInVwcGVycXVhcnRpbGUiKSAjIyBDb21wdXRlIG5vcm1hbGl6aW5nIGZhY3RvcnMgLS0+CjwhLS0gIyBkX3RtbSA8LSBjYWxjTm9ybUZhY3RvcnMoZCwgbWV0aG9kID0gIlRNTSIpICMjIENvbXB1dGUgbm9ybWFsaXppbmcgZmFjdG9ycyAtLT4KPCEtLSAjIGRfcTMgPC0gY2FsY05vcm1GYWN0b3JzKGQsIG1ldGhvZCA9ICJ1cHBlcnF1YXJ0aWxlIikgIyMgQ29tcHV0ZSBub3JtYWxpemluZyBmYWN0b3JzIC0tPgo8IS0tICMgcGxvdChkX3RtbSRzYW1wbGVzJG5vcm0uZmFjdG9ycywgZF9xMyRzYW1wbGVzJG5vcm0uZmFjdG9ycykgLS0+CjwhLS0gIyBjcG1fcTMgPC0gY3BtKGRfcTMpIC0tPgo8IS0tICMgYXBwbHkoY3BtKGRfcTMpLCAyLCBxdWFudGlsZSwgcHJvYiA9IDAuNzUpIC0tPgo8IS0tICMgYXBwbHkoY3BtKGRfdG1tKSwgMiwgcXVhbnRpbGUsIHByb2IgPSAwLjc1KSAtLT4KCjwhLS0gIyMgU3RvcmUgdGhlIHNjYWxpbmcgZmFjdG9yIGluIHRoZSBtZXRhZGF0YSAtLT4KPCEtLSBmYV9tZXRhJHNjYWxpbmcuZmFjdG9yIDwtIGQkc2FtcGxlcyRub3JtLmZhY3RvcnMgLS0+Cgo8IS0tICMjIENyZWF0ZSBhIHNlcGFyYXRlIGRhdGEuZnJhbWUgd2l0aCB0aGUgc3RhbmRhcmRpc2VkIGNvdW50cyAtLT4KPCEtLSBmYV9leHByX3RtbSA8LSBmYV9leHByX3JhdyAjIyBBIHF1aWNrIHdheSB0byBoYXZlIHRoZSBzYW1lIHNpemUgYW5kIHJvdyBuYW1lcyBhbmQgY29sdW1uIG5hbWVzIC0tPgo8IS0tIGZvciAocyBpbiAxOm5jb2woZmFfZXhwcl90bW0pKSB7IC0tPgo8IS0tICAgZmFfZXhwcl90bW1bLCBzXSA8LSBmYV9leHByX3Jhd1ssIHNdIC8gZmFfbWV0YSRzY2FsaW5nLmZhY3RvcltzXSAtLT4KPCEtLSB9IC0tPgo8IS0tICMgcmFuZ2UoZmFfZXhwcl90bW0pIC0tPgo8IS0tICMgbWVhbih1bmxpc3QoZmFfZXhwcl90bW0pKSAtLT4KPCEtLSAjIHEzX3JhdyA8LSBhcHBseShmYV9leHByX3JhdywgMiwgcXVhbnRpbGUsIHByb2IgPSAwLjc1KSAtLT4KPCEtLSAjIHEzX3RtbSA8LSBhcHBseShmYV9leHByX3RtbSwgMiwgcXVhbnRpbGUsIHByb2IgPSAwLjc1KSAtLT4KPCEtLSAjIHBsb3QocTNfcmF3LCBxM190bW0pIC0tPgo8IS0tICMgc3VtbWFyeShmYV9leHByX3RtbSkgLS0+CjwhLS0gIyMgQ29tcHV0ZSB0aGUgbG9nMi10cmFuc2Zvcm1lZCBjb3VudHMgYWZ0ZXIgbm9ybWFsaXNhdGlvbiAtLT4KPCEtLSBmYV9leHByX3RtbV9sb2cyIDwtIGxvZzIoZmFfZXhwcl90bW0gKyBlcHNpbG9uKSAtLT4KCjwhLS0gYm94cGxvdChmYV9leHByX3RtbV9sb2cyLCBob3JpeiA9IFRSVUUpIC0tPgo8IS0tIGBgYCAtLT4KCgojIyMgU3RhbmRhcmRpc2F0aW9uIGVudHJlIMOpY2hhbnRpbGxvbnMKCk5vdXMgYXBwbGlxdW9ucyBpY2kgdW5lIG3DqXRob2RlIHNpbXBsZSBtYWlzIGVmZmljYWNlIGRlIHN0YW5kYXJkaXNhdGlvbgoKYGBge3Igbm9ybWFsaXNhdGlvbl9xM30KIyMjIyBJbnRlci1zYW1wbGUgc3RhbmRhcmRpc2F0aW9uIG9uIHRoZSBRMyBvZiByYXcgY291bnRzICMjIyMKdG90YWxfcTMgPC0gcXVhbnRpbGUodW5saXN0KGZhX2V4cHJfZmlsdGVyZWQpLCBwcm9icyA9IDAuNzUpCnNhbXBsZV9zdGF0X3ByZW5vcm0kUTNfZmlsdGVyZCA8LSBhcHBseShmYV9leHByX2ZpbHRlcmVkLCAyLCBxdWFudGlsZSwgcHJvYnMgPSAwLjc1KQpzYW1wbGVfc3RhdF9wcmVub3JtJHNjYWxlX2ZhY3RvciA8LSAxIC8gc2FtcGxlX3N0YXRfcHJlbm9ybSRRM19maWx0ZXJkICogdG90YWxfcTMKCiMjIEFwcGx5IHN0YW5kYXJkaXNhdGlvbgpmYV9leHByX3N0YW5kYXJkIDwtIHQodChmYV9leHByX2ZpbHRlcmVkKSAqIHVubGlzdChzYW1wbGVfc3RhdF9wcmVub3JtJHNjYWxlX2ZhY3RvcikpCiMjIENoZWNrIDNyZCBxdWFudGlsZSBhZnRlciBzdGFuZGFyZGlzYXRpb24Ka2FibGUoYXBwbHkoZmFfZXhwcl9zdGFuZGFyZCwgMiwgcXVhbnRpbGUsIHByb2JzID0gMC43NSksIAogICAgICBjb2wubmFtZXMgPSAiUTNfc3RhbmRhcmRpc2VkIiwgCiAgICAgIGNhcHRpb24gPSAiVGhpcmQgcXVhcnRpbGUgb2YgdGhlIGZpbHRlcmVkIGNvdW50cyBhZnRlciBpbnRlci1zYW1wbGUgc3RhbmRhcmRpc2F0aW9uIG9mIHRoZSB0aGlyZCBxdWFydGlsZXMuICIpCiMgYm94cGxvdChmYV9leHByX3N0YW5kYXJkLCBob3Jpem9udGFsID0gVFJVRSkKYGBgCgoKPCEtLSBgYGB7ciBzYW1wbGVfc3RhbmRhcmRpc2F0aW9ufSAtLT4KPCEtLSAjIyBHZW5lcmF0ZSBhIGRhdGEgZnJhbWUgd2hlcmUgbnVsbCB2YWx1ZXMgYXJlIHJlcGxhY2VkIGJ5IE5BIC0tPgo8IS0tIGZhX2V4cHJfbm9udWxsIDwtIGZhX2V4cHJfbG9nMl9maWx0ZXJlZCAtLT4KPCEtLSBmYV9leHByX25vbnVsbFtmYV9leHByX2xvZzJfZmlsdGVyZWQgPD0gMF0gPC0gTkEgLS0+CjwhLS0gc3VtKGlzLm5hKGZhX2V4cHJfbm9udWxsKSkgLS0+Cgo8IS0tICMjIENvbXB1dGUgdGhlIDNyZCBxdWFydGlsZSBvZiBub24tbnVsbCB2YWx1ZXMgZm9yIGVhY2ggc2FtcGxlIGFuZCBzdG9yZSB0aGVtIGluIGEgdmVjdG9yOiAtLT4KPCEtLSBzYW1wbGVfcTNfbm9udWxsIDwtIGFwcGx5KGZhX2V4cHJfbm9udWxsLCAyLCBxdWFudGlsZSwgcHJvYiA9IDAuNzUsIG5hLnJtID0gVFJVRSkgLS0+CjwhLS0gIyBwcmludChzYW1wbGVfcTNfbm9udWxsKSAtLT4KCjwhLS0gIyMgQ29tcHV0ZSB0aGUgUTMgZm9yIGFsbCB0aGUgdmFsdWVzLCB3aGljaCB3aWxsIHNlcnZlIGFzIHRhcmdldCB2YWx1ZSBmb3IgdGhlIHN0YW5kYXJkaXNlZCBzYW1wbGUgUTMgLS0+CjwhLS0gYWxsX3EzX25vbnVsbCA8LSBxdWFudGlsZSh1bmxpc3QoZmFfZXhwcl9ub251bGwpLCBwcm9iID0gMC43NSwgbmEucm0gPSBUUlVFKSAtLT4KPCEtLSAjIHByaW50KGFsbF9xM19ub251bGwpIC0tPgoKPCEtLSAjIyBTdGFuZGFyZGlzZSBleHByZXNzaW9uIG9uIHRoZSB0aGlyZCBxdWFydGlsZSBvZiBub24tbnVsbCB2YWx1ZXMgLS0+CjwhLS0gIyMgQmV3YXJlIDogZm9yIHRoaXMgc3RhbmRhcmRpemF0aW9uIHdlIGtlZXAgdGhlIG51bGwgdmFsdWVzIC0tPgo8IS0tICMjIFRyaWNrIDogd2UgdHJhbnNwb3NlIHRoZSB0YWJsZSB0byBhcHBseSB0aGUgcmF0aW8gc2FtcGxlIHBlciBzYW1wbGUsICAtLT4KPCEtLSAjIyBhbmQgdGhlbiB0cmFuc3Bvc2UgdGhlIHJlc3VsdHMgdG8gZ2V0IGJhY2sgdGhlIGdlbmVzIGluIHJvd3MgYW5kIHNhbXBsZXMgaW4gY29sdW1ucyAtLT4KPCEtLSBmYV9leHByX2xvZzIgPC0gdCh0KGZhX2V4cHJfbG9nMl9maWx0ZXJlZCkgKiBhbGxfcTNfbm9udWxsIC8gc2FtcGxlX3EzX25vbnVsbCApIC0tPgo8IS0tICMgcXVhbnRpbGUodW5saXN0KGZhX2V4cHJfbG9nMiksIHByb2JzID0gMC43NSwgbmEucm0gPSBUUlVFKSAtLT4KCjwhLS0gIyMgV2UgYWxzbyBjb21wdXRlIHRoZSB2YWx1ZXMgZm9yIHRoZSAibm9udWxsIiB0YWJsZSBmb3IgIC0tPgo8IS0tICMjIHRoZSBzYWtlIG9mIGNvbXBhcmlzb24gYW5kIHRvIGNoZWNrIHRoYXQgdGhlIHRoaXJkIHF1YW50aWxlcyBvZiBub24tbnVsbCAgLS0+CjwhLS0gIyMgdmFsdWVzIGFyZSB3ZWxsIGlkZW50aWNhbCBhY3Jvc3Mgc2FtcGxlcy4gLS0+CjwhLS0gZmFfZXhwcl9sb2cyX25vbnVsbCA8LSB0KHQoZmFfZXhwcl9ub251bGwpICogYWxsX3EzX25vbnVsbCAvIHNhbXBsZV9xM19ub251bGwgKSAtLT4KPCEtLSAjIHF1YW50aWxlKHVubGlzdChmYV9leHByX2xvZzJfbm9udWxsKSwgcHJvYnMgPSAwLjc1LCBuYS5ybSA9IFRSVUUpIC0tPgoKPCEtLSAjIyBDb21wdXRlIFEzIGJlZm9yZSBhbmQgYWZ0ZXIgc3RhbmRhcmRpc2F0aW9uLCBpbmNsdWRpbmcgb3Igbm90IHRoZSBudWxsIHZhbHVlcyAtLT4KPCEtLSBzdGFuZGFyZGlzYXRpb25faW1wYWN0IDwtIGRhdGEuZnJhbWUoIC0tPgo8IS0tICAgYmVmb3JlX2FsbCA9IGFwcGx5KGZhX2V4cHJfbG9nMl9maWx0ZXJlZCwgMiwgcXVhbnRpbGUsIHByb2IgPSAgMC43NSwgbmEucm0gPSBUUlVFKSwgLS0+CjwhLS0gICBiZWZvcmVfbm9udWxsID0gYXBwbHkoZmFfZXhwcl9ub251bGwsIDIsIHF1YW50aWxlLCBwcm9iID0gIDAuNzUsIG5hLnJtID0gVFJVRSksIC0tPgo8IS0tICAgYWZ0ZXJfbm9udWwgPSBhcHBseShmYV9leHByX2xvZzJfbm9udWxsLCAyLCBxdWFudGlsZSwgcHJvYiA9ICAwLjc1LCBuYS5ybSA9IFRSVUUpLCAtLT4KPCEtLSAgIGFmdGVyX2FsbCA9IGFwcGx5KGZhX2V4cHJfbG9nMiwgMiwgcXVhbnRpbGUsIHByb2IgPSAgMC43NSwgbmEucm0gPSBUUlVFKSAtLT4KPCEtLSApIC0tPgoKPCEtLSAjIyBOb3RlOiBhZnRlciBzdGFuZGFyZGl6YXRpb24gdGhlIFEzIG9mIHRoZSBkYXRhIHNob3cgc29tZSB2YXJpYXRpb25zICAtLT4KPCEtLSAjIyBiZWNhdXNlIHdlIGNvbXB1dGUgdGhlbSBoZXJlIHdpdGggdGhlIG51bGwgdmFsdWVzIC0tPgo8IS0tIGthYmxlKHN0YW5kYXJkaXNhdGlvbl9pbXBhY3QsIGNhcHRpb24gPSAiSW1wYWN0IG9mIHN0YW5kYXJkaXphdGlvbiBvbiB0aGUgdGhpcmQgcXVhbnRpbGUgKFEzKSBwZXIgc2FtcGxlLiBUaGlyZCBxdWFudGlsZXMgYXJlIGNvbXB1dGVkIGJlZm9yZSBhbmQgYWZ0ZXIgc3RhbmRhcmRpc2F0aW9uLCB3aXRoIGVpdGhlciBhbGwgdGhlIHZhbHVlcyBvZiB0aGUgZmlsdGVyZWQgdGFibGUsIG9yIG9ubHkgdGhlIG5vbi1udWxsIHZhbHVlcy4gIikgLS0+CjwhLS0gYGBgIC0tPgoKCiMjIyBUcmFuc2Zvcm1hdGlvbiBsb2cyCgpOb3VzIGFwcGxpcXVvbnMgdW5lIHRyYW5zZm9ybWF0aW9uIGVuIGxvZzIgZGVzIGRvbm7DqWVzIGJydXRlcywgYXByw6hzIGF2b2lyIGFqb3V0w6kgdW4gZXBzaWxvbiAkXGVwc2lsb24gPSAxJCAobGVzIHZhbGV1cnMgbnVsbGVzIHNlcm9udCBkb25jIHJlcHLDqXNlbnTDqWVzIHBhciB1biBsb2cyKGNvdW50cykgdmFsYW50ICQwJC4gTm91cyBzdG9ja29ucyBsZSByw6lzdWx0YXQgZGFucyB1biBkYXRhLmZyYW1lIG5vbW3DqSBgZmFfZXhwcl9sb2cyYC4KCk5vdXMgYWZmaWNob25zIHVuIGZyYWdtZW50IGRlcyB0YWJsZWF1eCBgZmFfZXhwcl9yYXdgIGV0IGBmYV9leHByX2xvZzJgIGVuIHPDqWxlY3Rpb25uYW50IGxlcyBsaWduZXMgMTAwIMOgIDEwOSBldCBsZXMgY29sb25uZXMgNSDDoCAxMCwgYWZpbiBkZSBub3VzIGFzc3VyZXIgcXVlIGxhIHRyYW5zZm9ybWF0aW9uIGVuIGxvZzIgYSBiaWVuIGZvbmN0aW9ubsOpLiAKCmBgYHtyIGxvZzJfdHJhbnNmb3JtfQojIyBMb2cyIHRyYW5zZm9ybWF0aW9uIG9mIHRoZSB0cmFuc2NyaXB0b21lIGRhdGEKZXBzaWxvbiA8LSAxCmZhX2V4cHJfbG9nMiA8LSBsb2cyKGZhX2V4cHJfc3RhbmRhcmQgKyBlcHNpbG9uKQojIGRpbShmYV9leHByX2xvZzIpCiMgVmlldyhoZWFkKGZhX2V4cHJfbG9nMikpCgojIyBEaXNwbGF5IG9mIGEgZnJhZ21lbnQgb2YgdGhlIGRhdGEgYmVmb3JlIGFuZCBhZnRlciBsb2cyIHRyYW5zZm9ybWF0aW9uCmthYmxlKGZhX2V4cHJfcmF3WzEwMDoxMDksIDU6MTBdLCBjYXB0aW9uID0gIkZyYWdtZW50IGRlcyBkb25uw6llcyB0cmFuc2NyaXB0b21pcXVlcyBicnV0ZXMiKQprYWJsZShmYV9leHByX2xvZzJbMTAwOjEwOSwgNToxMF0sIGNhcHRpb24gPSAiRnJhZ21lbnQgZGVzIGRvbm7DqWVzIHRyYW5zY3JpcHRvbWlxdWVzIGFwcsOocyB0cmFuc2Zvcm1hdGlvbiBsb2cyIikKYGBgCgojIyAzLiBTdGF0aXN0aXF1ZXMgZGVzY3JpcHRpdmVzIHN1ciBsZXMgZG9ubsOpZXMgbm9ybWFsaXPDqWVzCgoqKipBIHZvdXMgZGUgam91ZXIhKioqCgojIyMgU3RhdGlzdGlxdWVzIHBhciBnw6huZSBhcHLDqHMgbm9ybWFsaXNhdGlvbgoKR8OpbsOpcmV6IHVuIGRhdGEuZnJhbWUgYXZlYyB1bmUgbGlnbmUgcGFyIGfDqG5lIMOgIHBhcnRpciBkdSB0YWJsZWF1IGRlIGRvbm7DqWVzIG5vcm1hbGlzw6llcywgYXZlYyBsZXMgc3RhdGlzdGlxdWVzIHN1aXZhbnRlcyAodW5lIHN0YXRpc3RpcXVlIHBhciBjb2xvbm5lKToKCi0gbW95ZW5uZQotIHZhcmlhbmNlCi0gw6ljYXJ0LXR5cGUKLSBjb2VmZmljaWVudCBkZSB2YXJpYXRpb24gKMOpY2FydC10eXBlIGRpdmlzw6kgcGFyIGxhIG1veWVubmUpCi0gaW50ZXJ2YWxsZSBpbnRlci1xdWFydGlsZXMKLSBtaW5pbXVtCi0gbcOpZGlhbmUKLSBtYXhpbXVtCgpgYGB7ciBnZW5lX3N0YXRfcG9zdF9ub3JtfQojIyBHZW5lLXdpc2Ugc3RhdGlzdGljcyBhZnRlciBub3JtYWxpc2F0aW9uCm1lc3NhZ2UoIkNvbXB1dGluZyBnZW5lLXdpc2Ugc3RhdGlzdGljcyBvbiBsb2cyLXRyYW5zZm9ybWVkIGFuZCBub3JtYWxpc2VkIGNvdW50cyIpCmdlbmVfc3RhdF9ub3JtIDwtIGRhdGEuZnJhbWUoCiAgbWVhbiA9IGFwcGx5KGZhX2V4cHJfbG9nMiwgMSwgbWVhbiwgbmEucm0gPSBGKSwKICB2YXIgPSBhcHBseShmYV9leHByX2xvZzIsIDEsIHZhciwgbmEucm0gPSBUUlVFKSwKICBzZCA9IGFwcGx5KGZhX2V4cHJfbG9nMiwgMSwgc2QsIG5hLnJtID0gRiksCiAgQ1YgPSBOQSwKICBtaW4gPSBhcHBseShmYV9leHByX2xvZzIsIDEsIG1pbiwgbmEucm0gPSBUUlVFKSwKICBRMSA9IGFwcGx5KGZhX2V4cHJfbG9nMiwgMSwgcXVhbnRpbGUsIHAgPSAwLjI1LCBuYS5ybSA9IFRSVUUpLAogIG1lZGlhbiA9IGFwcGx5KGZhX2V4cHJfbG9nMiwgMSwgbWVkaWFuLCBuYS5ybSA9IFRSVUUpLAogIFEzID0gYXBwbHkoZmFfZXhwcl9sb2cyLCAxLCBxdWFudGlsZSwgcCA9IDAuNzUsIG5hLnJtID0gVFJVRSksCiAgbWF4ID0gYXBwbHkoZmFfZXhwcl9sb2cyLCAxLCBtYXgsIG5hLnJtID0gVFJVRSksCiAgbnVsbCA9IGFwcGx5KGZhX2V4cHJfbG9nMiA9PSAwLCAxLCBzdW0sIG5hLnJtID0gVFJVRSkKICApCmdlbmVfc3RhdF9ub3JtJENWIDwtIGdlbmVfc3RhdF9ub3JtJHNkIC8gZ2VuZV9zdGF0X25vcm0kbWVhbgpgYGAKCiMjIyBBbm5vdGF0aW9uIGRlcyBnw6huZXMKCkNoYXF1ZSBnw6huZSDDqXRhbnQgZG9ubsOpIHBhciBzb24gaWRlbnRpZmlhbnQgZGFucyBsYSBiYXNlIGRlIGRvbm7DqWVzIEVOU0VNQkwgdm91cyB1dGlsaXNlcmV6IGxlIGBwYXF1ZXQgYmlvbWFSdCBkZSBiaW9jb25kdWN0b3JgIHBvdXIgYWpvdXRlciBkZXMgYW5ub3RhdGlvbnMgOiBzeW1ib2xlLCBjaHJvbW9zb21lLCBjb29yZG9ubsOpZXMgZ8Opbm9taXF1ZXMsIGJyaW4uIApTdWl2ZXogcGFzIMOgIHBhcyBsYSBtw6l0aG9kZSBwcm9wb3PDqWUgKCoqKmNlcnRhaW5lcyDDqXRhcGVzIHBldXZlbnQgcHJlbmRyZSBxdWVscXVlcyBtaW51dGVzKioqKToKCiAtIGNoYXJnZXogbGUgcGFxdWV0IGJpb21hUnQsIHZvaXJlIGluc3RhbGxlci1sZSB1bmlxdWVtZW50IHNpIG7DqWNlc3NhaXJlLiBJbmRpcXVleiBsZSBjb2RlIMOgIGwnZW1wbGFjZW1lbnQgYWTDqXF1YXQgZGFucyBkZSAuUm1kLgoKIC0gc8OpbGVjdGlvbm5leiBsYSBiYXNlIGRlIGRvbm7DqWVzIEVOU0VNQkwgYXZlYyBsYSBmb25jdGlvbiBgdXNlTWFydCgpYC4gQXR0ZW50aW9uIMOgIGNob2lzaXIgbGUgYm9uIGfDqW5vbWUgYXZlYyBsJ2FndW1lbnQgYGRhdGFzZXRgOiBgbW11c2N1bHVzX2dlbmVfZW5zZW1ibGAKIAogLSBhdmVjIGxhIGZvbmN0aW9uIGBnZXRCTSgpYCByw6ljdXDDqXJleiBkZSBsYSBiYXNlIGRlIGRvbm7DqWVzIEVOU0VNQkwgbGVzIGNoYW1wcyBkZW1hbmTDqXMgKCoqKnBvdXIgc3ltYm9sZSB1dGlsaXNleiBleHRlcm5hbF9nZW5lX25hbWUqKiopIGVuIGFwcGxpcXVhbnQgImVuc2VtYmxfZ2VuZWlkIiBwb3VyIGwnYWd1bWVudCBgZmlsdGVyYCBldCBlbiBpbmRpcXVhbnQgcG91ciBsJ2FyZ3VtZW50IGB2YWx1ZXNgIGxlIHZlY3RldXIgZGVzIGlkZW50aWZpYW50cyBkZXMgZ8OobmVzIHByw6lzZW50cyBkYW5zIGxlIGRhdGFmcmFtZSBgZ2VuZV9zdGF0X25vcm1gLiBWb3VzIG9idGVuZXogdW4gZGF0YWZyYW1lLgogCkEgcHLDqXNlbnQsIGFqb3V0ZXogYXUgZGF0YWZyYW1lIGBnZW5lX3N0YXRfbm9ybWAgZW4gMcOocmVzIGNvbG9ubmVzIGxlcyBhbm5vdGF0aW9ucyByZXRyb3V2w6llcyBncsOiY2Ugw6AgYmlvbWFSdC4gQXR0ZW50aW9uLCBjZXJ0YWlucyBnw6huZXMgbmUgc29udCBwYXMgcmV0cm91dsOpcyBkYW5zIGxhIHZlcnNpb24gZCdFTlNFTUJMIHN1ciBiaW9tYVJ0IGRvbmMgbGFpc3NleiBkZXMgTkEgY29tbWUgZG9ubsOpZXMgbWFucXVhbnRlcyBkYW5zIGNlIGNhcy4gTm91cyB2b3VzIHJlY29tbWFuZG9ucyBkJ3V0aWxpc2VyIGxhIGZ1bmN0aW9uIGBtZXJnZSgpYCBkZSBSIGJhc2Ugb3UgYmllbiBgbGVmdF9qb2luKClgIGRlIGBkcGx5cmAgcG91ciBmdXNpb25uZXIgbGVzIGRldXggZGF0YWZyYW1lcyBlbiB1biBzZXVsLgogCmBgYHtyIGdlbmVfYW5ub3RhdGlvbnMsIGV2YWw9RkFMU0V9CiMjIyBHZW5lIGFubm90YXRpb25zICMjIyMKCiMjIE9wZW4gYSBjb25uZWN0aW9uIHRvIEVuc2VtYmwgTUFSVAptZXNzYWdlKCJPcGVuaW5nIGNvbm5lY3Rpb24gdG8gRW5zZW1ibCBNQVJUIikKZW5zZW1ibCA8LSB1c2VNYXJ0KCJFTlNFTUJMX01BUlRfRU5TRU1CTCIsIAogICAgICAgICAgICAgICAgICAgaG9zdCA9ICJ3d3cuZW5zZW1ibC5vcmciLCAKICAgICAgICAgICAgICAgICAgIGRhdGFzZXQgPSAibW11c2N1bHVzX2dlbmVfZW5zZW1ibCIpCgojIyBHZXQgZ2VuZSBhbm5vdGF0aW9ucwptZXNzYWdlKCJHZXR0aW5nIGdlbmUgYW5ub3RhdGlvbnMiKQpnZW5lcyA8LSBnZXRCTShhdHRyaWJ1dGVzID0gYygiZW5zZW1ibF9nZW5lX2lkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJleHRlcm5hbF9nZW5lX25hbWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNocm9tb3NvbWVfbmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzdGFydF9wb3NpdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZW5kX3Bvc2l0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzdHJhbmQiKSwgCiAgICAgICAgICAgICAgIGZpbHRlciA9ICJlbnNlbWJsX2dlbmVfaWQiLAogICAgICAgICAgICAgICB2YWx1ZXMgPSByb3cubmFtZXMoZ2VuZV9zdGF0X25vcm0pLAogICAgICAgICAgICAgICBtYXJ0ID0gZW5zZW1ibCkKICAKIyMgTWVyZ2UgZ2VuZSBhbm5vdGF0aW9ucyBhbmQgZXhwcmVzc2lvbiBzdGF0aXN0aWNzCmdlbmVfc3RhdF9ub3JtIDwtIG1lcmdlKGdlbmVzLCBnZW5lX3N0YXRfbm9ybSwgYnkueCA9ICJlbnNlbWJsX2dlbmVfaWQiLCBieS55ID0gMCwgc29ydCA9IEZBTFNFKQoKa2FibGUoZ2VuZV9zdGF0X25vcm1bMTAwOjEwOSwgXSwgY2FwdGlvbiA9ICJHZW5lLXdpc2Ugc3RhdGlzdGljcyBhZnRlciBub3JtYWxpc2F0aW9uIikKYGBgCgoqKkNoYWxsZW5nZSBmYWxjdWx0YXRpZjoqKgoKUsOpb3Jkb25uZXogbGVzIGfDqG5lcyBwYXIgcG9zaXRpb24gZ8Opbm9taXF1ZSBldCBhZmZpY2hleiBsZXMgbGlnbmVzIDUgcHJlbWnDqHJlcyBldCAgNSBkZXJuacOocmVzIGxpZ25lcyBkZSBjZSB0YWJsZWF1IGRlIHN0YXRpc3RpcXVlcy4gCgpgYGB7ciBzb3J0X2dlbmVzX2J5X2Nocm9tLCBldmFsPUZBTFNFfQoKZ2VuZV9zdGF0X25vcm0gPC0gZ2VuZV9zdGF0X25vcm1bb3JkZXIoZ2VuZV9zdGF0X25vcm0kY2hyb21vc29tZV9uYW1lLCBnZW5lX3N0YXRfbm9ybSRzdGFydF9wb3NpdGlvbiksXQoKa2FibGUoZ2VuZV9zdGF0X25vcm1bYygxOjUsIChucm93KGdlbmVfc3RhdF9ub3JtKSAtIDQpOm5yb3coZ2VuZV9zdGF0X25vcm0pKSwgXSwgCiAgICAgIGNhcHRpb24gPSAiR2VuZS13aXNlIHN0YXRpc3RpY3MgYWZ0ZXIgbm9ybWFsaXNhdGlvbi4iKQpgYGAKCgojIyMgRGlzdHJpYnV0aW9uIGRlcyBkb25uw6llcwoKLSBEZXNzaW5leiBzb3VzIGZvcm1lIGQndW4gaGlzdG9ncmFtbWUgbGEgZGlzdHJpYnV0aW9uIGRlcyB2YWxldXJzIGFwcsOocyBub3JtYWxpc2F0aW9uICh0b3VzIMOpY2hhbnRpbGxvbnMgY29uZm9uZHVzKQoKYGBge3IgZmFfZXhwcl9ub3JtX2Rpc3RyaWIsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTUsIG91dC53aWR0aD0iNzAlIiwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIGV4cHJlc3Npb24gdmFsdWVzIChsb2cyIGNvdW50cykgYWZ0ZXIgZ2VuZSBmaWx0ZXJpbmcgYW5kIHN0YW5kYXJkaXNhdGlvbiBvbiB0aGUgc2FtcGxlLXdpc2UgdGhpcmQtcXVhcnRpbGUgb2Ygbm9uLW51bGwgdmFsdWVzLiBUaGUgdmVydGljYWwgbGluZSBoaWdobGlnaHRzIHRoZSBtZWFuIHZhbHVlLiAifQpoaXN0KHVubGlzdChmYV9leHByX2xvZzIpLCAKICAgICBicmVha3MgPSBzZXEoZnJvbSA9IDAsIHRvID0gbWF4KGZhX2V4cHJfbG9nMikgKyAxLCBieSA9IDAuMjUpLAogICAgIHhsYWIgPSAibG9nMihjb3VudHMpIGFmdGVyIHN0YW5kYXJkaXNhdGlvbiIsIAogICAgIHlsYWIgPSAibnVtYmVyIG9mIGdlbmVzIGFmdGVyIGZpbHRlcmluZyIsCiAgICAgY29sID0gIiNCQkRERkYiLAogICAgIGxhcyA9IDEsIGNleC5heGlzID0gMC44LAogICAgIG1haW4gPSAiZGlzdHJpYnV0aW9uIGFmdGVyIHN0YW5kYXJkaXNhdGlvbiIpCmFibGluZSh2ID0gbWVhbihmYV9leHByX2xvZzIpLCBjb2wgPSAiZGFya2dyZWVuIiwgbHdkID0gMikKYGBgCgotIERlc3NpbmV6IHVuIGJveCBwbG90IHBhciDDqWNoYW50aWxsb24gYXZhbnQgZXQgYXByw6hzIG5vcm1hbGlzYXRpb24sIGV0IGNvbW1lbnRleiBsYSBmYcOnb24gZG9udCBsJ2VmZmV0IGRlIGxhIG5vcm1hbGlzYXRpb24gYXBwYXJhw650IHN1ciBjZXMgZ3JhcGhpcXVlcy4gCgpgYGB7ciBib3hwbG90c19zdGFuZGFyZGlzYXRpb25faW1wYWN0LCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTIsIG91dC53aWR0aD0iMTAwJSIsIGZpZy5jYXA9IkJveCBwbG90cyBzaG93aW5nIHRoZSBpbXBhY3Qgb2Ygbm9ybWFsaXNhdGlvbiJ9CiMjIyMgQm94IHBsb3RzIHRvIHNob3cgbm9ybWFsaXNhdGlvbiBpbXBhY3QgIyMjIwpwYXIobWFyID0gYyg0LDYsNCwxKSkgIyMgU2V0IHRoZSBtYXJnaW5zCnBhcihtZnJvdyA9IGMoMiwyKSkKYm94cGxvdChmYV9leHByX3JhdywgCiAgICAgICAgaG9yaXpvbnRhbCA9IFRSVUUsCiAgICAgICAgeGxhYiA9ICJjb3VudHMiLCAKICAgICAgICBsYXMgPSAxLCAKICAgICAgICBjb2wgPSBmYV9tZXRhJGNvbG9yLCAKICAgICAgICBtYWluID0gIlJhdyBjb3VudHMsIGFsbCBnZW5lcyIpCmJveHBsb3QoZmFfZXhwcl9maWx0ZXJlZCwgCiAgICAgICAgaG9yaXpvbnRhbCA9IFRSVUUsIAogICAgICAgIHhsYWIgPSAiY291bnRzIiwgCiAgICAgICAgbGFzID0gMSwgCiAgICAgICAgY29sID0gZmFfbWV0YSRjb2xvciwgCiAgICAgICAgbWFpbiA9ICJSYXcgY291bnRzLCBmaWx0ZXJlZCBnZW5lcyIpCmJveHBsb3QoZmFfZXhwcl9zdGFuZGFyZCwgCiAgICAgICAgaG9yaXpvbnRhbCA9IFRSVUUsIAogICAgICAgIHhsYWIgPSAiY291bnRzIiwgCiAgICAgICAgbGFzID0gMSwgCiAgICAgICAgY29sID0gZmFfbWV0YSRjb2xvciwgCiAgICAgICAgbWFpbiA9ICJTdGFuZGFyZGlzZWQgY291bnRzIChzYW1wbGUgUTMpIikKYm94cGxvdChmYV9leHByX2xvZzIsIAogICAgICAgIHhsYWIgPSAibG9nMihjb3VudHMpIiwgCiAgICAgICAgbGFzID0gMSwgCiAgICAgICAgaG9yaXpvbnRhbCA9IFRSVUUsIAogICAgICAgIGNvbCA9IGZhX21ldGEkY29sb3IsIAogICAgICAgIG1haW4gPSAiTm9ybWFsaXNlZCBjb3VudHMiKQpwYXIobWZyb3cgPSBjKDEsIDEpKQpwYXIobWFyID0gYyg0LDUsNSwxKSkKYGBgCgojIyA0LiBBbmFseXNlIGRlIHJlZ3JvdXBlbWVudCBkZXMgZG9ubsOpZXMKCioqKkEgdm91cyBkZSBqb3VlciEqKioKCiMjIyBTw6lsZWN0aW9uIGRlIGfDqG5lcyBkJ2V4cHJlc3Npb24gw6lsZXbDqWUgZXQgdmFyaWFibGUKClBvdXIgcsOpZHVpcmUgbGUgbm9tYnJlIGRlIGfDqG5lcywgbm91cyBhbGxvbnMgw6ljYXJ0ZXIgbGVzIGfDqG5lcyBmYWlibGVtZW50IGV4cHJpbcOpcyAobG9nMiBtb3llbiBpbmbDqXJpZXVyIMOgIDQpLCBldCBuZSByZXRlbmlyIHF1ZSBjZXV4IHF1aSBtb250cmVudCBkZXMgdmFyaWF0aW9ucyBpbXBvcnRhbnRlcyBlbnRyZSDDqWNoYW50aWxsb25zLiBQb3VyIGNlIGRlcm5pZXIgY3JpdMOocmUsIG5vdXMgbm91cyBiYXNvbnMgc3VyIGxhIHZhcmlhbmNlLiAKCjwhLS0gU8OpbGVjdGlvbm5leiBsZXMgZ8OobmVzIGF5YW50IHVuIG5pdmVhdSBsb2cyIG1veWVuIG1pbmltYWwgc3Vww6lyaWV1ciDDoCAzICgkbSA+IDMkKSBldCB1biBjb2VmZmljaWVudCBkZSB2YXJpYXRpb24gc3Vww6lyaWV1ciDDoCAwLjUgKCRDViA+IDAuNSQpLiBOb3RlOiBjZXMgdmFsZXVycyBzb250IHBhcmZhaXRlbWVudCBhcmJpdHJhaXJlcywgZWxsZXMgb250IMOpdMOpIGNob2lzaWVzIHBvdXIgb2J0ZW5pciB1biBub21icmUgcmFpc29ubmFibGUgZGUgZ8OobmVzLiAgLS0+CgpTw6lsZWN0aW9ubmV6IGxlcyBnw6huZXMgYXlhbnQgdW4gbml2ZWF1IGxvZzIgbW95ZW4gbWluaW1hbCBzdXDDqXJpZXVyIMOgIDUgKCRtID4gNSQpIGV0IHVuZSB2YXJpYW5jZSBzdXDDqXJpZXVyZSDDoCAyICgkc14yID4gMiQpLiBOb3RlOiBjZXMgdmFsZXVycyBzb250IHBhcmZhaXRlbWVudCBhcmJpdHJhaXJlcywgZWxsZXMgb250IMOpdMOpIGNob2lzaWVzIHBvdXIgb2J0ZW5pciB1biBub21icmUgcmFpc29ubmFibGUgZGUgZ8OobmVzLiAKCmBgYHtyIGdlbmVfc2VsZWN0aW9ufQojIyBDb21wdXRlIGEgQm9vbGVhbiB2ZWN0b3IgaW5kaWNhdGluZyB3aGV0aGVyIGVhY2ggZ2VuZSBwYXNzZXMgb3Igbm90IHRoZSBleHByZXNzaW9uIGxldmVsIHRocmVzaG9sZApoaWdoX2V4cHJlc3Npb24gPC0gZ2VuZV9zdGF0X25vcm0kbWVhbiA+IDUKIyB0YWJsZShoaWdoX2V4cHJlc3Npb24pICMgY291bnQgbnVtYmVyIG9mIGdlbmVzIHdpdGggaGlnaC93ZWFrIGV4cHJlc3Npb24KCiMjIENvbXB1dGUgYSBCb29sZWFuIHZlY3RvciBpbmRpY2F0aW5nIHdoZXRoZXIgZWFjaCBnZW5lIHBhc3NlcyBvciBub3QgdGhlIHZhcmlhdGlvbiBjb2VmZmljaWVudCB0aHJlc2hvbGQKaGlnaF92YXJpYXRpb24gPC0gZ2VuZV9zdGF0X25vcm0kQ1YgPiAwLjUKIyB0YWJsZShoaWdoX3ZhcmlhdGlvbikgIyBjb3VudCBudW1iZXIgb2YgZ2VuZXMgd2l0aCB3ZWFrIGhpZ2ggY29lZmZmaWNpZW50IG9mIHZhcmlhdGlvbgoKIyMgQ29tcHV0ZSBhIEJvb2xlYW4gdmVjdG9yIGluZGljYXRpbmcgd2hldGhlciBlYWNoIGdlbmUgcGFzc2VzIG9yIG5vdCB0aGUgdmFyaWFuY2UgdGhyZXNob2xkCmhpZ2hfdmFyaWFuY2UgPC0gZ2VuZV9zdGF0X25vcm0kdmFyID4gMgojIHRhYmxlKGhpZ2hfdmFyaWFuY2UpICMgY291bnQgbnVtYmVyIG9mIGdlbmVzIHdpdGggd2VhayBoaWdoIHZhcmlhbmNlCgojICMjIFNlbGVjdCBnZW5lcyBoYXZpbmcgYm90aCBhIGhpZ2ggbWVhbiBleHByZXNzaW9uIGFuZCBhIGhpZ2ggdmFyaWF0aW9uIGNvZWZmaWNpZW4KIyBzZWxlY3RlZF9nZW5lcyA8LSBoaWdoX3ZhcmlhdGlvbiAmIGhpZ2hfZXhwcmVzc2lvbgojIyBTZWxlY3QgZ2VuZXMgaGF2aW5nIGJvdGggYSBoaWdoIG1lYW4gZXhwcmVzc2lvbiBhbmQgYSBoaWdoIHZhcmlhbmNlCnNlbGVjdGVkX2dlbmVzIDwtIGhpZ2hfdmFyaWFuY2UgJiBoaWdoX2V4cHJlc3Npb24KIyB0YWJsZShzZWxlY3RlZF9nZW5lcykgIyBjb3VudCBudW1iZXIgb2YgZ2VuZXMgd2l0aCB3ZWFrIGhpZ2ggY29lZmZmaWNpZW50IG9mIHZhcmlhdGlvbgpwcmludChwYXN0ZTAoIlNlbGVjdGVkIGdlbmVzOiAiLCBzdW0oc2VsZWN0ZWRfZ2VuZXMpKSkKCiMjIENyZWF0ZSBhIGRhdGEgZnJhbWUgd2l0aCB0aGUgZXhwcmVzc2lvbiBvZiB0aGUgc2VsZWN0ZWQgZ2VuZXMKZmFfZXhwcl9zZWxlY3RlZCA8LSBmYV9leHByX2xvZzJbc2VsZWN0ZWRfZ2VuZXMsIF0KYGBgCgpEZXNzaW5leiBkZXMgaGlzdG9ncmFtbWVzIGRlcyB2YWxldXJzIGQnZXhwcmVzc2lvbiBhdmFudCBldCBhcHLDqHMgY2V0dGUgc8OpbGVjdGlvbiBkZSBnw6huZXMsIGV0IGNvbW1lbnRleiBsZXMgZGlmZsOpcmVuY2VzLiAKCmBgYHtyIGhpc3RfZXhwcl9zZWxlY3RlZF9nZW5lcywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Niwgb3V0LndpZHRoPSIxMDAlIiwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIGV4cHJlc3Npb24gdmFsdWVzIGJlZm9yZSBhbmQgYWZ0ZXIgZ2VuZSBzZWxlY3Rpb24ifQojIyMjIEhpc3RvZ3JhbXMgb2YgZXhwcmVzc2lvbiBiZWZvcmUgYW5kIGFmdGVyIGdlbmUgc2VsZWN0aW9uICMjIyMKCnBhcihtZnJvdyA9IGMoMiwxKSkKaGlzdCh1bmxpc3QoZmFfZXhwcl9sb2cyKSwgCiAgICAgYnJlYWtzID0gc2VxKGZyb20gPSAwLCB0byA9IG1heChmYV9leHByX2xvZzIpICsgMSwgYnkgPSAwLjI1KSwKICAgICBsYXMgPSAxLCAKICAgICBjZXguYXhpcyA9IDAuOCwgCiAgICAgbWFpbiA9ICJTdGFuZGFyZGl6ZWQgdmFsdWVzIGJlZm9yZSBnZW5lIHNlbGVjdGlvbiIsCiAgICAgY29sID0gICIjRERCQkZGIikKCmhpc3QodW5saXN0KGZhX2V4cHJfc2VsZWN0ZWQpLCAKICAgICBicmVha3MgPSBzZXEoZnJvbSA9IDAsIHRvID0gbWF4KGZhX2V4cHJfbG9nMikgKyAxLCBieSA9IDAuMjUpLAogICAgIGxhcyA9IDEsIAogICAgIGNleC5heGlzID0gMC44LCAKICAgICBtYWluID0gIlN0YW5kYXJkaXplZCB2YWx1ZXMgYWZ0ZXIgZ2VuZSBzZWxlY3Rpb24iLAogICAgIGNvbCA9ICAiI0ZGRERCQiIpCgpwYXIobWZyb3cgPSBjKDEsMSkpCgoKIyAjIyBTb21lIHF1aWNrIGNoZWNrczogdGhlIHNlbGVjdGlvbiBvZiBoaWdobHkgdmFyaWFibGUgZ2VuZXMgc2VsZWN0IHRob3NlIGhhdmluZyBtYW55IHplcm9zIC0gYW5kIGhpZ2ggdmFsdWVzIGluIG90aGVyIHNhbXBsZXMKIyBoaXN0KHVubGlzdChmYV9leHByX2xvZzJfZmlsdGVyZWRbaGlnaF9leHByZXNzaW9uLCBdKSwgYnJlYWtzPTEwMCkKIyBoaXN0KHVubGlzdChmYV9leHByX2xvZzJfZmlsdGVyZWRbaGlnaF92YXJpYXRpb24sIF0pLCBicmVha3M9MTAwKQojIGhpc3QodW5saXN0KGZhX2V4cHJfbG9nMl9maWx0ZXJlZFshaGlnaF92YXJpYXRpb24sIF0pLCBicmVha3M9MTAwKQojIGhpc3QodW5saXN0KGZhX2V4cHJfbG9nMl9maWx0ZXJlZFtzZWxlY3RlZF9nZW5lcywgXSksIGJyZWFrcz0xMDApCmBgYAoKRGVzc2luZXogdW4gYm94IHBsb3QgcGFyIMOpY2hhbnRpbGxvbiBkZXMgdmFsZXVycyBkJ2V4cHJlc3Npb24gYXZhbnQgZXQgYXByw6hzIHPDqWxlY3Rpb24gZGVzIGfDqG5lcywgZXQgY29tbWVudGV6IGxlIHLDqXN1bHRhdC4gCgpgYGB7ciBib3hwbG90c19leHByX3NlbGVjdGVkX2dlbmVzLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NSwgb3V0LndpZHRoPSI2MCUiLCBmaWcuY2FwPSJCb3ggcGxvdHMgb2Ygc3RhbmRhcmRpc2VkIGV4cHJlc3Npb24gdmFsdWVzIGJlZm9yZSBhbmQgYWZ0ZXIgZ2VuZSBzZWxlY3Rpb24uICJ9CiMjIyMgSGlzdG9ncmFtIG9mIGV4cHJlc3Npb24gYWZ0ZXIgZ2VuZSBzZWxlY3Rpb24gIyMjIwoKcGFyKG1mcm93ID0gYygxLDIpKQoKYm94cGxvdChmYV9leHByX2xvZzIsIAogICAgICAgIGhvcml6b250YWwgPSBUUlVFLAogICAgICAgIHhsYWIgPSAibG9nMihjb3VudHMpIiwgCiAgICAgICAgbGFzID0gMSwgCiAgICAgICAgY29sID0gZmFfbWV0YSRjb2xvciwgCiAgICAgICAgbWFpbiA9ICJCZWZvcmUgZ2VuZSBzZWxlY3Rpb24iKQpib3hwbG90KGZhX2V4cHJfc2VsZWN0ZWQsIAogICAgICAgIGhvcml6b250YWwgPSBUUlVFLAogICAgICAgIHhsYWIgPSAibG9nMihjb3VudHMpIiwgCiAgICAgICAgbGFzID0gMSwgCiAgICAgICAgY29sID0gZmFfbWV0YSRjb2xvciwgCiAgICAgICAgbWFpbiA9ICJBZnRlciBnZW5lIHNlbGVjdGlvbiIpCgpwYXIobWZyb3cgPSBjKDEsMSkpCmBgYAoKCiMjIyBBQ1AKCkRlc3NpbmV6IHVuIHBsb3QgQUNQIGRlcyDDqWNoYW50aWxsb25zIGVuIGxlcyBjb2xvcmFudCBwYXIgY29uZGl0aW9uIGF2YW50IGV0IGFwcsOocyBub3JtYWxpc2F0aW9uLgoKLSBhdmVjIGxlcyBjb21wdGFnZXMgYnJ1dHMgZGUgbGEgbWF0cmljZSBkJ2V4cHJlc3Npb24gaW5pdGlhbGUgKCRmYV9leHByJCkKCmBgYHtyIGFjcF9yYXdfYWxsX2dlbmVzLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD04LCBvdXQud2lkdGg9IjYwJSIsIGZpZy5jYXA9IlBDIHBsb3Qgb2YgdGhlIHNhbXBsZXMgZnJvbSB0aGUgcmF3IGV4cHJlc3Npb24gdmFsdWVzIG9mIGFsbCBnZW5lcy4gIn0KIyMgUmF3IGV4cHJlc3Npb24gdmFsdWVzLCBhbGwgZ2VuZXMKbWFfcGNhX3Jhd190dCA8LSBQQ0EodChmYV9leHByX3JhdyksIAogICAgICAgICAgICAgICAgICAgICAgc2NhbGUudW5pdCA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIGdyYXBoID0gRkFMU0UpCiMgcGxvdChtYV9wY2FfcmF3X3R0LCBjaG9peCA9ICJpbmQiKQpmdml6X3BjYV9pbmQobWFfcGNhX3Jhd190dCwgY29sLmluZCA9IGZhX21ldGFbLCJjb25kaXRpb24iXSkKYGBgCgo8IS0tIC0gYXZlYyBsZXMgY29tcHRhZ2VzIGJydXRzLCBtYWlzIGVuIHJlc3RyZWlnbmFudCBsJ2FuYWx5c2UgYXV4IGfDqG5lcyBzw6lsZWN0aW9ubsOpcyAoJGZhX2V4cHJfcmF3W3NlbGVjdGVkX2dlbmVzLF0kKSAtLT4KCgo8IS0tIGBgYHtyIGFjcF9yYXdfc2VsZWN0ZWRfZ2VuZXMsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTgsIG91dC53aWR0aD0iNjAlIiwgZmlnLmNhcD0iUEMgcGxvdCBvZiB0aGUgc2FtcGxlcyBmcm9tIHRoZSByYXcgZXhwcmVzc2lvbiB2YWx1ZXMgb2Ygc2VsZWN0ZWQgZ2VuZXMuICJ9IC0tPgo8IS0tICMjIFJhdyB2YWx1ZXMgd2l0aCBvbmx5IHRoZSBzZWxlY3RlZCBnZW5lcyAtLT4KPCEtLSBtYV9wY2FfcmF3X3NlbCA8LSBQQ0EodChmYV9leHByX3Jhd1tzZWxlY3RlZF9nZW5lcyxdKSwgIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgICBzY2FsZS51bml0ID0gRkFMU0UsICAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgZ3JhcGggPSBGQUxTRSkgLS0+CjwhLS0gZnZpel9wY2FfaW5kKG1hX3BjYV9yYXdfc2VsLCBjb2wuaW5kID0gZmFfbWV0YVssICJjb2xvciJdKSAtLT4KPCEtLSBgYGAgLS0+CgoKLSBhdmVjIGxhIG1hdHJpY2UgZGUgdmFsZXVycyBub3JtYWxpc8OpZXMgZGVzIGfDqG5lcyBmaWx0csOpcwoKYGBge3IgYWNwX25vcm1fZmlsdGVyZWRfZ2VuZXMsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTgsIG91dC53aWR0aD0iNjAlIiwgZmlnLmNhcD0iUEMgcGxvdCBvZiB0aGUgc2FtcGxlcyBmcm9tIG5vcm1hbGlzZWQgY291bnRzLCBiZWZvcmUgZ2VuZSBzZWxlY3Rpb24uICJ9Cm1hX3BjYV9maWx0ZXJlZCA8LSBQQ0EodChmYV9leHByX2xvZzIpLCBzY2FsZS51bml0ID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgIGdyYXBoID0gRkFMU0UpCiMgcGxvdChtYV9wY2FfZmlsdGVyZWQsIGNob2l4ID0gInZhciIpCiMgcGxvdChtYV9wY2Ffc2VsLCBjaG9peCA9ICJpbmQiKQpmdml6X3BjYV9pbmQobWFfcGNhX2ZpbHRlcmVkLCBjb2wuaW5kID0gZmFfbWV0YVssICJjb25kaXRpb24iXSkKYGBgCgotIGF2ZWMgbGEgbWF0cmljZSBmaW5hbGUgKHRyYW5zZm9ybWF0aW9uIGxvZzIsIGZpbHRyZSBkZXMgZ8OobmVzIG5vbi1kw6l0ZWN0w6lzLCBzdGFuZGFyZGlzYXRpb24gZXQgc8OpbGVjdGlvbiBkZXMgZ8OobmVzIGZvcnRlbWVudCBleHByaW3DqXMgZXQgw6AgaGF1dCBjb2VmZmljaWVudCBkZSB2YXJpYXRpb24pCgpgYGB7ciBhY3Bfbm9ybV9zZWxlY3RlZF9nZW5lcywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OCwgb3V0LndpZHRoPSI2MCUiLCBmaWcuY2FwPSJQQyBwbG90IG9mIHRoZSBzYW1wbGVzIGZyb20gbm9ybWFsaXNlZCB2YWx1ZXMsIGFmdGVyIGdlbmUgc2VsZWN0aW9uLiAifQptYV9wY2Ffc2VsIDwtIFBDQSh0KGZhX2V4cHJfc2VsZWN0ZWQpLCBzY2FsZS51bml0ID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgIGdyYXBoID0gRkFMU0UpCiMgcGxvdChtYV9wY2Ffc2VsLCBjaG9peCA9ICJ2YXIiKQojIHBsb3QobWFfcGNhX3NlbCwgY2hvaXggPSAiaW5kIikKZnZpel9wY2FfaW5kKG1hX3BjYV9zZWwsIGNvbC5pbmQgPSBmYV9tZXRhWywgImNvbmRpdGlvbiJdKQpgYGAKCiMjIyBDbHVzdGVyaW5nCgotIENhbGN1bGV6IGxlcyBtYXRyaWNlcyBkZSBkaXN0YW5jZSBlbnRyZSDDqWNoYW50aWxsb25zLCBlbiB1dGlsaXNhbnQgcmVzcGVjdGl2ZW1lbnQgbGVzIGRpc3RhbmNlcyBldWNsaWRpZW5uZSAoYGRpc3QoKWApLCBjb2VmZmljaWVudCBkZSBQZWFyc29uIChgY29yKCwgbWV0aG9kID0gInBlYXJzb24iKWApICBldCBkZSBTcGVhcm1hbiAoYGNvcigsIG1ldGhvZCA9ICJzcGVhcm1hbiIpYCkuCgoKYGBge3Igc2FtcGxlX2Rpc3RhbmNlc30KIyMjIyBTYW1wbGUgZGlzdGFuY2VzICMjIyMKZGlzdF9ldWNfc2FtcGxlcyA8LSBkaXN0KHQoZmFfZXhwcl9zZWxlY3RlZCkpCmNvcl9wZWFyc29uX3NhbXBsZXMgPC0gYXMuZGlzdCgxIC0gY29yKGZhX2V4cHJfc2VsZWN0ZWQpKQpjb3Jfc3BlYXJtYW5fc2FtcGxlcyA8LSBhcy5kaXN0KDEgLSBjb3IoZmFfZXhwcl9zZWxlY3RlZCwgbWV0aG9kID0gInNwZWFybWFuIikpCmBgYAoKLSBFZmZlY3R1ZXogdW4gY2x1c3RlcmluZyBoacOpcmFyY2hpcXVlIGRlcyDDqWNoYW50aWxsb25zLCBlbiB1dGlsaXNhbnQgbGUgY3JpdMOocmUgImNvbXBsZXRlIiBwb3VyIGwnYWdnbG9tw6lyYXRpb24uIENvbXBhcmV6IGxlcyBhcmJyZXMgZCfDqWNoYW50aWxsb25zIG9idGVudXMgYXZlYyBjZXMgdHJvaXMgbcOpdHJpcXVlcyBldCBjaG9pc2lzc2V6IGNlbGxlIHF1aSB2b3VzIHBhcmHDrnQgbGEgcGx1cyBwZXJ0aW5lbnRlLgoKYGBge3Igc2FtcGxlX2NsdXN0ZXJpbmcsIGZpZy53aWR0aD0xMiwgcGxvdC5oZWlnaHQ9NSwgb3V0LndpZHRoPSIxMDAlIiwgZmlnLmNhcD0iU2FtcGxlIHRyZWUgd2l0aCB0aHJlZSBhbHRlcm5hdGl2ZSBkaXN0YW5jZSBtZXRyaWNzOiBFdWNsaWRpYW50IGRpc3RhbmNlIChsZWZ0KSwgUGVhcnNvbiBjb3JyZWxhdGlvbiAoY2VudGVyKSwgU3BlYXJtYW4gY29ycmVsYXRpb24gKHJpZ2h0KS4/ICJ9CiMjIyMgU2FtcGxlIGNsdXN0ZXJpbmcgIyMjIwpwYXIobWZyb3cgPSBjKDEsMykpCnBsb3QoaGNsdXN0KGRpc3RfZXVjX3NhbXBsZXMpLCBoYW5nID0gLTEsCiAgICAgbWFpbiA9ICJldWNsaWRlYW4gZGlzdGFuY2UiKQpwbG90KGhjbHVzdChjb3JfcGVhcnNvbl9zYW1wbGVzKSwgaGFuZyA9IC0xLAogICAgIG1haW4gPSAicGVhcnNvbiIpCnBsb3QoaGNsdXN0KGNvcl9zcGVhcm1hbl9zYW1wbGVzKSwgaGFuZyA9IC0xLAogICAgIG1haW4gPSAic3BlYXJtYW4iKQpwYXIobWZyb3cgPSBjKDEsMSkpCmBgYAoKLSBFZmZlY3R1ZXogdW4gY2x1c3RlcmluZyBoacOpcmFyY2hpcXVlIGRlcyBnw6huZXMgZW4gdXRpbGlzYW50IGxhIGRpc3RhbmNlIGJhc8OpZSBzdXIgbGUgY29lZmZpY2llbnQgZGUgUGVhcnNvbiBldCBsZSBjcml0w6hyZSBkZSBXYXJkCgpgYGB7ciBnZW5lX3RyZWV9CiMjIyMgR2VuZSB0cmVlIHdpdGggUGVhcnNvbiBjb3JyZWxhdGlvbiAjIyMjCmNsdXN0ZXJpbmdfbWV0aG9kIDwtICJjb21wbGV0ZSIgIyMgQ2hvb3NlIGEgY2x1c3RlcmluZyBtZXRob2QKY29yX3BlYXJzb25fZ2VuZXMgPC0gIGFzLmRpc3QoMSAtIGNvcih0KGZhX2V4cHJfc2VsZWN0ZWQpKSkKCiMjIEJ1aWxkIGEgZ2VuZSB0cmVlCmdlbmVfdHJlZV9wZWFyc29uIDwtIGhjbHVzdChjb3JfcGVhcnNvbl9nZW5lcywgbWV0aG9kID0gY2x1c3RlcmluZ19tZXRob2QpCgojIyBQbG90IHRoZSBnZW5lIHRyZWUKcGxvdChnZW5lX3RyZWVfcGVhcnNvbiwgaGFuZyA9IC0xLCBsYXMgPSAxLCAKICAgICBtYWluID0gcGFzdGUwKCJHZW5lIHRyZWU7IFBlYXJzb24gY29lZmZpY2llbnQ7ICIsIGNsdXN0ZXJpbmdfbWV0aG9kLCAiIGNsdXN0ZXJpbmciKSwgCiAgICAgbGFiZWxzID0gRkFMU0UpCmBgYAoKLSBEZXNzaW5leiB1biBhcmJyZSBhdmVjIGxlIHLDqXN1bHRhdCBkdSBjbHVzdGVyaW5nIGRlcyBnw6huZXMgZXQgY29tbWVudGV6IHNhIHN0cnVjdHVyZS4gU2kgdm91cyBkZXZpZXogY2hvaXNpciBkZSBmYcOnb24gYXJiaXRyYWlyZSB1biBub21icmUgZGUgY2x1c3RlcnMsIHF1ZSBjaG9pc2lyaWV6LXZvdXMgPyBQb3VycXVvaSA/IFBhcyBkZSBwYW5pcXVlLCBub3VzIHBvdXZvbnMgYXNzdW1lciBpY2kgcXVlIGxhIHLDqXBvbnNlIGNvbXBvcnRlIHVuZSBwYXJ0IGRlIHN1YmplY3Rpdml0w6kuIAoKYGBge3IgZ2VuZV90cmVlX3dpdGhfYm94ZXN9CiMjIyMgUGxvdCB0aGUgZ2VuZSB0cmVlIHdpdGggYm94ZXMgdG8gZGVub3RlIHRoZSBjbHVzdGVycyAjIyMjCnBsb3QoZ2VuZV90cmVlX3BlYXJzb24sIGhhbmcgPSAtMSwKICAgICBtYWluID0gcGFzdGUwKCJHZW5lIHRyZWUgd2l0aCA3IGNsdXN0ZXJzOyBQZWFyc29uIGNvZWZmaWNpZW50OyAiLCBjbHVzdGVyaW5nX21ldGhvZCwgIiBjbHVzdGVyaW5nIiksIAogICAgIGxhYmVscyA9IEZBTFNFKQpyZWN0LmhjbHVzdChnZW5lX3RyZWVfcGVhcnNvbiwgayA9IDcpCmBgYAoKLSBEZXNzaW5leiB1bmUgaGVhdG1hcCBkdSByw6lzdWx0YXQsIGVuIHPDqWxlY3Rpb25uYW50IGxlcyBkZXV4IHLDqXN1bHRhdHMgZGUgY2x1c3RlcmluZyBjaS1kZXNzdXMgcG91ciBsZXMgZ8OobmVzIGV0IGxlcyDDqWNoYW50aWxsb25zLiAKCmBgYHtyIGhlYXRtYXBfYmljbHVzdGVyaW5nLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OCwgb3V0LndpZHRoPSI5MCUiLCBmaWcuY2FwPSJIZWF0bWFwIHNob3dpbmcgdGhlIGJpY2x1c3RlcmluZyBvZiBnZW5lcyBhbmQgc2FtcGxlcy4gIn0KIyMjIyBIZWF0bWFwICMjIyMKcGhlYXRtYXAodChmYV9leHByX3NlbGVjdGVkKSwgCiAgICAgICAgIG1haW4gPSBwYXN0ZTAoIkJpY2x1c3RlcmluZzsgIiwgIlBlYXJzb24gY29ycmVsYXRpb247ICIsIGNsdXN0ZXJpbmdfbWV0aG9kLCAiIGNsdXN0ZXJpbmciKSwKICAgICAgICAgbGFiZWxzX2NvbCA9ICIiLCAKICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSBjbHVzdGVyaW5nX21ldGhvZCwgCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scyA9ICJjb3JyZWxhdGlvbiIsIAogICAgICAgICBjbHVzdGVyaW5nX2Rpc3RhbmNlX3Jvd3MgPSAiY29ycmVsYXRpb24iKQpgYGAKCi0gRGVzc2luZXogdW5lIGhlYXRtYXAgZHUgcsOpc3VsdGF0LCBlbiBhZmZpY2hhbnQgdW4gYXJicmUgc3VyIGxlcyBnw6huZXMgbWFpcyBwYXMgc3VyIGxlcyDDqWNoYW50aWxsb25zCgpgYGB7ciBiaWNsdXN0ZXJpbmd9CnBoZWF0bWFwKHQoZmFfZXhwcl9zZWxlY3RlZCksIAogICAgICAgICBtYWluID0gcGFzdGUwKCJHZW5lIGNsdXN0ZXJpbmc7ICIsICJQZWFyc29uIGNvcnJlbGF0aW9uOyAiLCBjbHVzdGVyaW5nX21ldGhvZCwgIiBjbHVzdGVyaW5nIiksCiAgICAgICAgIGxhYmVsc19jb2wgPSAiIiwgCiAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kID0gY2x1c3RlcmluZ19tZXRob2QsIAogICAgICAgICBjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHMgPSAiY29ycmVsYXRpb24iLCAKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UpCmBgYAoKCkludGVycHLDqXRleiBsZXMgcsOpc3VsdGF0cyBlbiBxdWVscXVlcyBwaHJhc2VzLiAKCgojIyA1LiBFbnJpY2hpc3NlbWVudCBmb25jdGlvbm5lbAoKKioqQSB2b3VzIGRlIGpvdWVyISoqKgoKRWZmZWN0dWV6IHVuZSBhbmFseXNlIGQnZW5yaWNoaXNzZW1lbnQgZm9uY3Rpb25uZWwgYXZlYyBsZXMgcHJpbmNpcGF1eCBjbHVzdGVycyBvYnRlbnVzIGRhbnMgbGEgc2VjdGlvbiBwcsOpY8OpZGVudGUuIAoKYGBge3IgZnVuY3Rpb25hbF9lbnJpY2htZW50fQojIyMjIFJ1biBlbnJpY2htZW50IGFuYWx5c2lzIHdpdGggZ29zdCgpICMjIyMKbWVzc2FnZSgiUnVubmluZyBlbnJpY2htZW50IGFuYWx5c2lzIHdpdGggZ29zdCIpCgojIyBHZXQgdGhlIGxpc3Qgb2YgSURzIGZvciB0aGUgc2VsZWN0ZWQgZ2VuZXMgIyMKZ2VuZV9pZHMgPC0gcm93bmFtZXMoZ2VuZV9zdGF0X25vcm0pW3NlbGVjdGVkX2dlbmVzXQoKIyMgR2V0IHRoZSBsaXN0IG9mIGdlbmUgbmFtZXMgZm9yIHRoZSBzZWxlY3RlZCBnZW5lcyAjIwojIGdlbmVfbmFtZXMgPC0gdW5saXN0KHN1YnNldCh4ID0gZ2VuZV9zdGF0X25vcm0sIAojICAgICAgICAgICAgICAgICAgICAgc3Vic2V0ID0gc2VsZWN0ZWRfZ2VuZXMsCiMgICAgICAgICAgICAgICAgICAgICBzZWxlY3QgPSBleHRlcm5hbF9nZW5lX25hbWUpKQojIGxlbmd0aChnZW5lX25hbWVzKQoKIyMKCmdvc3RyZXMgPC0gZ29zdChxdWVyeSA9IGdlbmVfaWRzLCAKICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gIm1tdXNjdWx1cyIsIAogICAgICAgICAgICAgICAgb3JkZXJlZF9xdWVyeSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgIG11bHRpX3F1ZXJ5ID0gRkFMU0UsIAogICAgICAgICAgICAgICAgc2lnbmlmaWNhbnQgPSBUUlVFLCAKICAgICAgICAgICAgICAgIGV4Y2x1ZGVfaWVhID0gRkFMU0UsIAogICAgICAgICAgICAgICAgbWVhc3VyZV91bmRlcnJlcHJlc2VudGF0aW9uID0gRkFMU0UsIAogICAgICAgICAgICAgICAgZXZjb2RlcyA9IEZBTFNFLCAKICAgICAgICAgICAgICAgIHVzZXJfdGhyZXNob2xkID0gMC4wNSwgCiAgICAgICAgICAgICAgICBjb3JyZWN0aW9uX21ldGhvZCA9ICJmZHIiLCAKICAgICAgICAgICAgICAgIGRvbWFpbl9zY29wZSA9ICJhbm5vdGF0ZWQiLCAKICAgICAgICAgICAgICAgIGN1c3RvbV9iZyA9IE5VTEwsIAogICAgICAgICAgICAgICAgbnVtZXJpY19ucyA9ICIiLCAKICAgICAgICAgICAgICAgIHNvdXJjZXMgPSBOVUxMLCAKICAgICAgICAgICAgICAgIGFzX3Nob3J0X2xpbmsgPSBGQUxTRSkKCgojIyBDaGVjayB0aGUgc3RydWN0dXJlIG9mIHRoZSByZXN1bHQKbmFtZXMoZ29zdHJlcykKbmFtZXMoZ29zdHJlcyRyZXN1bHQpCmthYmxlKHN1bW1hcnkoZ29zdHJlcykpCgojIFZpc3VhbGl6YXRpb24KZ29zdHBsb3QoZ29zdHJlcywgY2FwcGVkID0gVFJVRSwgaW50ZXJhY3RpdmUgPSBUUlVFKQoKIyBoaXN0KGdvc3RyZXMkcmVzdWx0JHBfdmFsdWUsIGJyZWFrcz1zZXEoZnJvbT0wLCB0bz0xLCBieSA9IDAuMDUpKQoKIyMgQ2hlY2sgdGhlIG1vc3Qgc2lnbmlmaWNhbnQgcmVzdWx0cywgZm9ybWF0aW5nIGZvciBrYWJsZQojaGVhZChnb3N0cmVzJHJlc3VsdCkKZW5yaWNoX29yZGVyIDwtIG9yZGVyKGdvc3RyZXMkcmVzdWx0JHBfdmFsdWUsIGRlY3JlYXNpbmcgPSBGQUxTRSkKc29ydGVkX3Jlc3VsdCA8LSBnb3N0cmVzJHJlc3VsdFtlbnJpY2hfb3JkZXIsIF0Ka2FibGUoaGVhZChzb3J0ZWRfcmVzdWx0LCBuID0gMTApLCAKICAgICAgZGlnaXRzID0gYygwLCAwLCAxNSwgNywgNywgNywgMywgMywgMCwgMCwgNywgNywgMCwgMCksIAogICAgICBjYXB0aW9uID0gIlRvcCAxMCBtb3N0IHNpZ25pZmljYW50IGVucmljaGVkIGZ1bmN0aW9uYWwgY2xhc3NlcyIpCiMga2FibGUoaGVhZChnb3N0cmVzJHJlc3VsdCksIAojICAgICAgIGZvcm1hdCA9IGMoIiVzIiwgIiVzIiwgIiVlIiwgIiVkIiwgIiVkIiwgIiVkIiwgIiUuM2YiLCAiJS4zZiIsICIlcyIsICIlcyIsICIlZCIsICIlZCIsICIlcyIsICIlcyIpKQpuYW1lcyhnb3N0cmVzJG1ldGEpCmBgYAoKIyMgQ29uY2x1c2lvbnMgZ8OpbsOpcmFsZXMKCgpSw6lzdW1leiBlbiBxdWVscXVlcyBwaHJhc2VzIHZvcyBjb25jbHVzaW9ucyDDoCBwYXJ0aXIgZGVzIHLDqXN1bHRhdHMgb2J0ZW51cy4gCgoKIyMgU2Vzc2lvbiBpbmZvCgoKYGBge3Igc2Vzc2lvbl9pbmZvfQojIyMjIFNlc3Npb24gaW5mbyAjIyMjCnNlc3Npb25JbmZvKCkKCmBgYAoK